diff --git a/.cspell.json b/.cspell.json index 9ed86f948..0b8165155 100644 --- a/.cspell.json +++ b/.cspell.json @@ -25,9 +25,11 @@ "micromark", "milestoned", "Numberish", + "OPENAI", "orgname", "pavlovcik", "permisson", + "Postgrest", "prereleased", "probot", "Probot", @@ -42,6 +44,7 @@ "Supabase", "SUPABASE", "svgs", + "tiktoken", "timelabel", "TURL", "typebox", @@ -49,6 +52,7 @@ "ubiquibot", "unarchived", "Unassigning", + "upserted", "Upserting", "URLSAFE", "vitalik", diff --git a/.env.example b/.env.example index f98c6d575..c9098afa3 100644 --- a/.env.example +++ b/.env.example @@ -7,22 +7,7 @@ WEBHOOK_SECRET= SUPABASE_URL= SUPABASE_KEY= -AUTO_PAY_MODE= -ANALYTICS_MODE= - -# Use `trace` to get verbose logging or `info` to show less +# `fatal` `error` `info` `verbose` `debug` LOG_LEVEL=debug -OPENAI_API_HOST=https://api.openai.com OPENAI_API_KEY= -CHATGPT_USER_PROMPT_FOR_IMPORTANT_WORDS="I need your help to find important words (e.g. unique adjectives) from github issue below and I want to parse them easily so please separate them using #(No other contexts needed). Please separate the words by # so I can parse them easily. Please answer simply as I only need the important words. Here is the issue content.\n" -CHATGPT_USER_PROMPT_FOR_MEASURE_SIMILARITY='I have two github issues and I need to measure the possibility of the 2 issues are the same content (No other contents needed and give me only the number in %).\n Give me in number format and add % after the number.\nDo not tell other things since I only need the number (e.g. 85%). Here are two issues:\n 1. "%first%"\n2. "%second%"' -SIMILARITY_THRESHOLD=80 -MEASURE_SIMILARITY_AI_TEMPERATURE=0 -IMPORTANT_WORDS_AI_TEMPERATURE=0 - -# Telegram Log Notification Envs -LOG_WEBHOOK_BOT_URL= # URL of cloudflare worker without trailing / -LOG_WEBHOOK_SECRET= # Random Secret, Shared between the telegram bot and the sender -LOG_WEBHOOK_GROUP_ID= # Group Id, ex: -100124234325 -LOG_WEBHOOK_TOPIC_ID= # Topic Id (Optional), Only provide if group is a topic and you're not using General \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index 5ee71efb0..e93d19143 100644 --- a/.eslintrc +++ b/.eslintrc @@ -7,6 +7,50 @@ "plugins": ["@typescript-eslint"], "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], "rules": { - "@typescript-eslint/no-floating-promises": "error" + "arrow-body-style": ["error", "as-needed"], // Allow single-line arrow functions without braces + "prefer-arrow-callback": ["error", { "allowNamedFunctions": false }], // Allow arrow functions for callbacks + "func-style": ["error", "declaration", { "allowArrowFunctions": false }], // Enforce function declarations and named functions + // ... other rules ... + + "@typescript-eslint/no-floating-promises": "error", + "@typescript-eslint/naming-convention": [ + "error", + { "selector": "typeLike", "format": ["PascalCase"] }, + { "selector": "variableLike", "format": ["camelCase"] }, + { "selector": "memberLike", "modifiers": ["private"], "format": ["camelCase"], "leadingUnderscore": "require" }, + { + "selector": "variable", + "types": ["boolean"], + "format": ["PascalCase"], + "prefix": ["is", "should", "has", "can", "did", "will", "does"] + }, + { + "selector": "variable", + "format": ["camelCase", "UPPER_CASE"], + "leadingUnderscore": "allow", + "trailingUnderscore": "allow" + }, + { "selector": "typeParameter", "format": ["PascalCase"], "prefix": ["T"] }, + { "selector": "interface", "format": ["PascalCase"], "custom": { "regex": "^I[A-Z]", "match": false } }, + { "selector": ["function", "variable"], "format": ["camelCase"] }, + { "selector": "variable", "modifiers": ["destructured"], "format": null }, + { "selector": "variable", "format": ["camelCase"], "leadingUnderscore": "allow", "trailingUnderscore": "allow" }, + + { + "selector": "parameter", + "format": ["camelCase"], + "leadingUnderscore": "allow", // This allows the use of a leading underscore + "trailingUnderscore": "allow" // This allows the use of a trailing underscore + }, + { + "selector": "parameter", + "format": null, + "filter": { + // This allows parameters to be named as just an underscore + "regex": "^_$", + "match": true + } + } + ] } } diff --git a/.github/ISSUE_TEMPLATE/bounty-template.yml b/.github/ISSUE_TEMPLATE/task-template.yml similarity index 91% rename from .github/ISSUE_TEMPLATE/bounty-template.yml rename to .github/ISSUE_TEMPLATE/task-template.yml index 7e81ebf0c..35eb1a763 100644 --- a/.github/ISSUE_TEMPLATE/bounty-template.yml +++ b/.github/ISSUE_TEMPLATE/task-template.yml @@ -1,14 +1,14 @@ -name: "Bounty Proposal" +name: "Task Proposal" description: Have a suggestion for how to improve UbiquiBot? Let us know! -title: "Bounty Proposal: " +title: "Task Proposal: " body: - type: markdown attributes: value: | ## Feature Request Form - Thank you for taking the time to file a feature request. - If you register your wallet address, you will be eligible for compensation if this is accepted! + Thank you for taking the time to file a feature request. + If you register your wallet address, you will be eligible for compensation if this is accepted! Please let us know how we can improve the bot. - type: textarea @@ -17,14 +17,14 @@ body: description: Please let us know what inspired you to write this proposal. Backlinking to specific comments on GitHub, and leaving a remark about how the bot should have interacted with it is usually sufficient context. validations: required: false - + - type: textarea attributes: label: Describe the solution description: A clear description of what you want to happen. Add any considered drawbacks. validations: required: true - + - type: textarea attributes: label: Remarks diff --git a/.github/ubiquibot-config.yml b/.github/ubiquibot-config.yml deleted file mode 100644 index c72441334..000000000 --- a/.github/ubiquibot-config.yml +++ /dev/null @@ -1,9 +0,0 @@ -price-multiplier: 1.5 -command-settings: - - name: start - enabled: false -# newContributorGreeting: -# enabled: true -# header: "Thank you for contributing to UbiquiBot! Please be sure to set your wallet address before completing your first bounty so that the automatic payout upon task completion will work for you." -# helpMenu: true -# footer: "###### Also please star this repository and [@ubiquity/devpool-directory](https://github.com/ubiquity/devpool-directory/) to show your support. It helps a lot!" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ae1b13c2f..a8d69174b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,6 +6,7 @@ on: jobs: build: runs-on: ubuntu-latest + steps: - name: Checkout repository uses: actions/checkout@v3 @@ -16,13 +17,13 @@ jobs: node-version: "20.10.0" - name: Install - run: yarn install + run: npm install -g bun && bun install - name: Local Build - run: yarn build + run: bun tsc - name: Lint - run: yarn lint + run: bun format run-migration: runs-on: ubuntu-latest @@ -31,7 +32,7 @@ jobs: env: SUPABASE_ACCESS_TOKEN: ${{ github.ref == 'refs/heads/main' && secrets.PRODUCTION_SUPABASE_ACCESS_TOKEN || secrets.STAGING_SUPABASE_ACCESS_TOKEN }} SUPABASE_DB_PASSWORD: ${{ github.ref == 'refs/heads/main' && secrets.PRODUCTION_SUPABASE_DB_PASSWORD || secrets.STAGING_SUPABASE_DB_PASSWORD }} - PROJECT_ID: ${{ github.ref == 'refs/heads/main' && secrets.PRODUCTION_SUPABASE_PROJECT_ID || secrets.STAGING_SUPABASE_PROJECT_ID }} + SUPABASE_PROJECT_ID: ${{ github.ref == 'refs/heads/main' && secrets.PRODUCTION_SUPABASE_PROJECT_ID || secrets.STAGING_SUPABASE_PROJECT_ID }} steps: - name: Checkout repository @@ -42,7 +43,7 @@ jobs: version: latest - name: Link Supabase project - run: supabase link --project-ref $PROJECT_ID + run: supabase link --project-ref $SUPABASE_PROJECT_ID - name: Run migrations run: supabase db push diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml new file mode 100644 index 000000000..045b04965 --- /dev/null +++ b/.github/workflows/e2e-test.yml @@ -0,0 +1,52 @@ +name: Run E2E Tests + +on: + - workflow_dispatch + - push + +jobs: + e2e-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20.10.0" + + - name: Install + run: npm install bun -g && bun install + + - name: Build + run: bun tsc + + - name: Test + env: + + APP_ID: ${{ secrets.APP_ID }} + # CHATGPT_USER_PROMPT_FOR_IMPORTANT_WORDS: + # CHATGPT_USER_PROMPT_FOR_MEASURE_SIMILARITY: + DISQUALIFY_TIME: "7 days" + FOLLOW_UP_TIME: "4 days" + # IMPORTANT_WORDS_AI_TEMPERATURE: + LOG_ENVIRONMENT: "production" + # LOG_LEVEL: + # MEASURE_SIMILARITY_AI_TEMPERATURE: + # OPENAI_API_HOST: + # OPENAI_API_KEY: + PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} + # SIMILARITY_THRESHOLD: + SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }} + SUPABASE_URL: ${{ secrets.SUPABASE_URL }} + TEST_ADMIN_PAT: ${{ secrets.TEST_ADMIN_PAT }} + TEST_ORGANIZATION_NAME: ${{ secrets.TEST_ORGANIZATION_NAME }} + TEST_OUTSIDE_COLLABORATOR_PAT: ${{ secrets.TEST_OUTSIDE_COLLABORATOR_PAT }} + TEST_REPOSITORY_NAME: ${{ secrets.TEST_REPOSITORY_NAME }} + WEBHOOK_PROXY_URL: ${{ secrets.WEBHOOK_PROXY_URL }} + WEBHOOK_SECRET: ${{ secrets.WEBHOOK_SECRET }} + X25519_PRIVATE_KEY: "QCDb30UHUkwJAGhLWC-R2N0PiEbd4vQY6qH2Wloybyo" + + run: "bun test" diff --git a/.github/workflows/kebab-case.yml b/.github/workflows/kebab-case.yml index b743c71c3..e0df26ad1 100644 --- a/.github/workflows/kebab-case.yml +++ b/.github/workflows/kebab-case.yml @@ -22,9 +22,12 @@ jobs: "^\.\/vendor" "^\.\/test" "^\.\/\.next" + "^\.\/tests" "\.sql$" "\.md$" - "\.d.ts$" + "\.d\.ts$" + "\.gitignore$" # Ignore .gitignore files + "\.test\.ts$" # Ignore .test.ts files ) while read -r file; do basefile=$(basename "$file") @@ -48,4 +51,4 @@ jobs: echo " - $file" done exit 1 - fi \ No newline at end of file + fi diff --git a/.github/workflows/knip.yml b/.github/workflows/knip.yml new file mode 100644 index 000000000..2b67061ce --- /dev/null +++ b/.github/workflows/knip.yml @@ -0,0 +1,30 @@ +name: Knip + +on: + pull_request: + +permissions: write-all + +jobs: + run-knip: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20.10.0 + + - name: Install toolchain + run: npm install -g bun && bun install + + - name: Report knip results to pull request + uses: Codex-/knip-reporter@v2 + with: + verbose: true + comment_id: ${{ github.workflow }}-reporter + command_script_name: knip-ci + annotations: true + ignore_results: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index fd84f4f64..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Releases -on: - create: - tag: - - "v*" - -jobs: - build: - runs-on: ubuntu-latest - permissions: - contents: write - steps: - # - - - name: Checkout repository - uses: actions/checkout@v3 - - # - - - name: Authenticate as UbiquiBot - uses: tibdex/github-app-token@v1.7.0 - id: get_installation_token - with: - app_id: ${{ secrets.APP_ID }} - private_key: ${{ secrets.APP_PRIVATE_KEY }} - - # - - - name: Create Release - uses: ncipollo/release-action@v1.12.0 - with: - token: ${{ steps.get_installation_token.outputs.token }} diff --git a/.github/workflows/short-files.yml b/.github/workflows/short-files.yml new file mode 100644 index 000000000..3a9f33810 --- /dev/null +++ b/.github/workflows/short-files.yml @@ -0,0 +1,28 @@ +name: Check File Length + +on: + push: + pull_request: + +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Check file length + run: | + IGNORE=("src/adapters/supabase/types/database.ts" "src/generatedFile2.ts") # Add more files to ignore as needed + find src -name "*.ts" -type f -exec bash -c ' + for ignore in "${IGNORE[@]}"; do + if [[ "$1" == "$ignore" ]]; then + echo "Ignoring $ignore" + exit 0 + fi + done + if [[ $(wc -l < "$1") -gt 512 ]]; then + echo "File $1 line length is greater than 512. This should be broken up into smaller files." + exit 1 + fi + ' bash {} \; \ No newline at end of file diff --git a/.gitignore b/.gitignore index fbd98adcd..cb57d7f65 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,6 @@ supabase/temp # Local Netlify folder .netlify bin -.yarn \ No newline at end of file +.yarn +yarn-error.log +tsconfig.tsbuildinfo diff --git a/.husky/commit-msg b/.husky/commit-msg index 4c49ae6ae..e4d3df482 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,4 +1,4 @@ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" -yarn commitlint --edit $1 +bun commitlint --edit "$1" diff --git a/.husky/pre-commit b/.husky/pre-commit index 44d21ba2f..eb534d6f2 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,5 @@ -#!/bin/sh +#!/usr/bin/env sh . "$(dirname "$0")/_/husky.sh" -yarn lint-staged --verbose \ No newline at end of file +# Run lint-staged first +bun lint-staged --verbose diff --git a/.netlify/functions/webhooks/webhooks.ts b/.netlify/functions/webhooks/webhooks.ts index 38833ea9d..f914cd922 100755 --- a/.netlify/functions/webhooks/webhooks.ts +++ b/.netlify/functions/webhooks/webhooks.ts @@ -1,32 +1,23 @@ -import { createProbot } from "probot"; -import { Handler } from "@netlify/functions"; -import { EmitterWebhookEventName } from "@octokit/webhooks"; - -import app from "../../../src"; +import sourceMapSupport from "source-map-support"; +sourceMapSupport.install(); +import { EmitterWebhookEventName } from "@octokit/webhooks"; +import { Context, createProbot } from "probot"; +import app from "../../../src/main"; const probot = createProbot(); const loadingApp = probot.load(app); - -export const handler: Handler = async (event, context) => { +export async function handler(event, _context: Context) { try { await loadingApp; await probot.webhooks.verifyAndReceive({ id: event.headers["X-GitHub-Delivery"] || event.headers["x-github-delivery"] || "", name: (event.headers["X-GitHub-Event"] || event.headers["x-github-event"]) as EmitterWebhookEventName, signature: event.headers["X-Hub-Signature-256"] || event.headers["x-hub-signature-256"] || "", - payload: JSON.parse(event.body!), + payload: JSON.parse(event.body), }); - - return { - statusCode: 200, - body: '{"ok":true}', - }; + return { statusCode: 200 }; // Success response } catch (error) { console.error(error); - - return { - statusCode: error.status || 500, - error: "ooops", - }; + return { statusCode: error.status || 500 }; // Error response } -}; +} diff --git a/.prettierrc b/.prettierrc index 55071e6d4..f1555f79b 100644 --- a/.prettierrc +++ b/.prettierrc @@ -3,7 +3,7 @@ "tabWidth": 2, "semi": true, "singleQuote": false, - "printWidth": 160, + "printWidth": 120, "htmlWhitespaceSensitivity": "strict", "plugins": [] } diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 8d0fc7144..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "files.exclude": { - "dist": true, - "node_modules": true, - "lib": true - }, - "explorer.excludeGitIgnore": false, - "cSpell.words": ["Probot", "Ubiqui"] -} diff --git a/.yarnrc.yml b/.yarnrc.yml deleted file mode 100644 index 3186f3f07..000000000 --- a/.yarnrc.yml +++ /dev/null @@ -1 +0,0 @@ -nodeLinker: node-modules diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f6ebb8125..d8cf0b82f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,39 +1,46 @@ ## Contributing -[fork]: /fork -[pr]: /compare -[code-of-conduct]: CODE_OF_CONDUCT.md +We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. -Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. - -Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms. +Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. ## Issues and PRs If you have suggestions for how this project could be improved, or want to report a bug, open an issue! We'd love all and any contributions. If you have questions, too, we'd love to hear them. -We'd also love PRs. If you're thinking of a large PR, we advise opening up an issue first to talk about it, though! Look at the links below if you're not sure how to open a PR. +We'd also love PRs. If you're thinking of a large PR, we advise opening up an issue first to talk about it. ## Submitting a pull request -1. [Fork][fork] and clone the repository. -1. Configure and install the dependencies: `npm install`. -1. Make sure the tests pass on your machine: `npm test`, note: these tests also apply the linter, so there's no need to lint separately. -1. Create a new branch: `git checkout -b my-branch-name`. -1. Make your change, add tests, and make sure the tests still pass. -1. Push to your fork and [submit a pull request][pr]. -1. Pat your self on the back and wait for your pull request to be reviewed and merged. +1. Fork and clone the repository. +2. Configure and install the dependencies: `bun install`. +3. Make sure the tests pass on your machine: `bun test`. These tests also apply the linter, so there's no need to lint separately. +4. Create a new branch: `git checkout -b my-branch-name`. +5. Make your change, add tests, and make sure the tests still pass. You can find the tests in the `src/tests` directory. +6. Push to your fork and submit a pull request. +7. Wait for your pull request to be reviewed and merged. Here are a few things you can do that will increase the likelihood of your pull request being accepted: -- Write and update tests. +- Write and update tests. You can find examples of how to do this in the `src/tests` directory. - Keep your changes as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests. -- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). +- Write a good commit message that conforms to (conventional commits)[https://www.conventionalcommits.org/]. This makes it easier to understand what your code is doing and why, which makes reviewing and maintaining it easier. Work in Progress pull requests are also welcome to get feedback early on, or if there is something blocked you. +## Running the project locally + +1. Fork and clone the repository. +2. Install dependencies: `bun install`. +3. Build the project: `bun tsc`. +4. Start the project: `bun start:watch`. + +## Environment Setup + +Copy `.env.example` to `.env` and update the fields with your own information. For more details, refer to the [Environment Setup](README.md#Environment-Setup) section in the README. + ## Resources - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) - [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) -- [GitHub Help](https://help.github.com) +- [GitHub Help](https://help.github.com) \ No newline at end of file diff --git a/README.md b/README.md index 20d2b4167..b28c00cc2 100644 --- a/README.md +++ b/README.md @@ -24,11 +24,12 @@ Ubiquity DAO's GitHub Bot for Automating DevPool Management. git clone https://github.com/ubiquity/ubiquibot.git cd ubiquibot -yarn -yarn build (to compile your changes) +bun +bun tsc (to compile your changes) -yarn build --watch (to locally auto compile your changes) -yarn start:watch +bun tsc --watch (to locally auto compile your changes) + +bun start:watch ## It's recommended to split terminals in your IDE while running above input ``` @@ -43,14 +44,14 @@ yarn start:watch - `DISQUALIFY_TIME`: (optional) Set a custom disqualify time (default: 7 days). - `OPENAI_API_HOST`: (optional) Set OpenAI host url (default: https://api.openai.com). - `OPENAI_API_KEY`: Set OpenAI key. -- `CHATGPT_USER_PROMPT_FOR_IMPORTANT_WORDS`: (optional) Set a custom user prompt for finding important words +- `CHATGPT_USER_PROMPT_FOR_IMPORTANT_WORDS`: (optional) Set a custom user prompt for finding important words (default: "I need your help to find important words (e.g. unique adjectives) from github issue below and I want to parse them easily so please separate them using #(No other contexts needed). Please separate the words by # so I can parse them easily. Please answer simply as I only need the important words. Here is the issue content.\n"). -- `CHATGPT_USER_PROMPT_FOR_MEASURE_SIMILARITY`: (optional) Set a custom user prompt for measuring similarity +- `CHATGPT_USER_PROMPT_FOR_MEASURE_SIMILARITY`: (optional) Set a custom user prompt for measuring similarity (default: 'I have two github issues and I need to measure the possibility of the 2 issues are the same content (No other contents needed and give me only the number in %).\n Give me in number format and add % after the number.\nDo not tell other things since I only need the number (e.g. 85%). Here are two issues:\n 1. "%first%"\n2. "%second%"'). - `SIMILARITY_THRESHOLD`: (optional) Set similarity threshold (default: 80). - `MEASURE_SIMILARITY_AI_TEMPERATURE`: (optional) Set ChatGPT temperature for measuring similarity (default: 0). - `IMPORTANT_WORDS_AI_TEMPERATURE`: (optional) Set ChatGPT temperature for finding important words (default: 0). -- `WEBHOOK_PROXY_URL`: (required) should be automatically filled when you install Ubiquibot +- `WEBHOOK_PROXY_URL`: (required) should be automatically filled when you install UbiquiBot - `WEBHOOK_SECRET`: (required) should be automatically filled when the app is installed `APP_ID` and `PRIVATE_KEY` are [here](https://t.me/c/1588400061/1627) for core team developers to use. @@ -100,7 +101,7 @@ If you are an external developer, `APP_ID`and `PRIVATE_KEY` are automatically ge ![trylocal](https://github.com/ubiquity/ubiquibot/assets/41552663/e958e7e4-6d42-44d1-a5cf-a090911f062c) -### Congratulations! you successfully installed Ubiquibot (new or to an existing app) +### Congratulations! you successfully installed UbiquiBot (new or to an existing app) ## Update an Existing Github App (bot) @@ -152,7 +153,7 @@ Instead, it is recommended to make a copy of the `.env.example` file and replace 1. Go to the [UbiquiBot App Marketplace](https://github.com/marketplace/ubiquibot) 2. Choose a plan and install UbiquiBot on your repository -3. Congratulations! You can now use the UbiquiBot to manage your bounties. +3. Congratulations! You can now use the UbiquiBot to manage your tasks. To test the bot, you can: @@ -165,14 +166,14 @@ To test the bot, you can: `evmNetworkId` is ID of the EVM-compatible network that will be used for payouts. -`priceMultiplier` is a base number that will be used to calculate bounty price based on the following formula: `price = priceMultiplier * timeLabelWeight * priority-label-weight * 100` +`priceMultiplier` is a base number that will be used to calculate task price based on the following formula: `price = priceMultiplier * timeLabelWeight * priority-label-weight * 100` -`timeLabels` are labels for marking the time limit of the bounty: +`timeLabels` are labels for marking the time limit of the task: - `name` is a human-readable name -- `value` is number of seconds that corresponds to the time limit of the bounty +- `value` is number of seconds that corresponds to the time limit of the task -`priorityLabels` are labels for marking the priority of the bounty: +`priorityLabels` are labels for marking the priority of the task: - `name` is a human-readable name @@ -187,7 +188,7 @@ To test the bot, you can: `disableAnalytics` can be `true` or `false` that disables or enables weekly analytics collection by Ubiquity. -`paymentPermitMaxPrice` sets the max amount for automatic payout of bounties when the issue is closed. +`paymentPermitMaxPrice` sets the max amount for automatic payout of tasks when the issue is closed. `commentIncentives` can be `true` or `false` that enable or disable comment incentives. These are payments generated for comments in the issue by contributors, excluding the assignee. @@ -202,7 +203,7 @@ To test the bot, you can: - `totals`: - `word` defines reward for each word in the comment -`maxConcurrentAssigns` is the maximum number of bounties that can be assigned to a bounty hunter at once. This excludes bounties with delayed or approved pull request reviews. +`maxConcurrentAssigns` is the maximum number of tasks that can be assigned to a task hunter at once. This excludes tasks with delayed or approved pull request reviews. `registerWalletWithVerification` can be `true` or `false`. If enabled, it requires a signed message to set wallet address. This prevents users from setting wallet address from centralized exchanges, which would make payments impossible to claim. @@ -227,12 +228,12 @@ Supabase comes with a [readme](https://github.com/ubiquity/ubiquibot/blob/develo ### This options will require you to have a local Docker installation (under the hood it is required by Supabase) refer to [Supabase Docs](https://supabase.com/docs) ``` -yarn supabase start +bun supabase start ``` ## Check Supabase Status (locally) ``` -yarn supabase status +bun supabase status ``` ![supabase](https://github.com/ubiquity/ubiquibot/assets/41552663/e8709b8f-e7c3-49e0-876c-c15dde22c6d2) @@ -251,16 +252,16 @@ DISQUALIFY_TIME="7 days" // 7 days ``` -3. `Make sure you have Node => 20 && yarn` +3. `Make sure you have Node => 20.10.0 && bun` 4. Open 2 terminal instances: - - in one instance run `yarn build --watch` (compiles the Typescript code) - - in another instance run `yarn start:watch` (runs the bot locally) + - in one instance run `bun tsc --watch` (compiles the Typescript code) + - in another instance run `bun start:watch` (runs the bot locally) 5. Open `http://localhost:3000` and follow instructions to add the bot to one of your repositories. At this point the `.env` files auto-fill the empty fields (`PRIVATE_KEY` and `APP_ID`) if it is not previously filled. -Now you can make changes to the repository on GitHub (e.g. add a bounty) and the bot should react. +Now you can make changes to the repository on GitHub (e.g. add a task) and the bot should react. -6. After adding the bot (as a installed app) to your github you will need to restart the aforemention yarn start:watch so CTRL-C to stop the node daemon and `yarn start:watch` again +6. After adding the bot (as a installed app) to your github you will need to restart the aforementioned `bun start:watch`` so CTRL-C to stop the node daemon and `bun start:watch` again You can, for example: @@ -271,9 +272,9 @@ You can, for example: ## How it works -Ubiquibot is built using the [probot](https://probot.github.io/) framework so in fact the bot is a github app. But thanks to the [probot/adapter-github-actions](https://github.com/probot/adapter-github-actions) you can also use the bot as a github action. +UbiquiBot is built using the [probot](https://probot.github.io/) framework so in fact the bot is a github app. But thanks to the [probot/adapter-github-actions](https://github.com/probot/adapter-github-actions) you can also use the bot as a github action. -[Ubiquibot](https://github.com/marketplace/ubiquibot) it's also available ready to install on the Githut Marketplace. +[UbiquiBot](https://github.com/marketplace/ubiquibot) it's also available ready to install on the GitHub Marketplace. When using as a github app the flow is the following: @@ -311,14 +312,14 @@ Make sure you have your local instance of [ubiquibot running](#quickstart). ## How to create a new release -1. Update the version in package.json: `yarn version --new-version x.x.x` +1. Update the version in package.json: `bun version --new-version x.x.x` 2. Commit and create a new tag: `git commit -am x.x.x && git tag -am x.x.x` 3. Push tags: `git push origin v"x.x.x"` 4. The Github action will create a release by recognizing the version tag ## Architecture Overview -Ubiquibot is built using the [probot](https://probot.github.io/) framework, the bot is a github app +UbiquiBot is built using the [probot](https://probot.github.io/) framework, the bot is a github app
 <root>
@@ -386,4 +387,4 @@ select
 
 -- Cancel the cron job
 select cron.unschedule('logs-cleaner');
-```
+```
\ No newline at end of file
diff --git a/bun.lockb b/bun.lockb
new file mode 100755
index 000000000..27c70cf08
Binary files /dev/null and b/bun.lockb differ
diff --git a/jest.config.js b/jest.config.js
new file mode 100644
index 000000000..73387ab61
--- /dev/null
+++ b/jest.config.js
@@ -0,0 +1,15 @@
+module.exports = {
+  "cache": false,
+  "maxConcurrency": 1,
+  "preset": "ts-jest",
+  "testEnvironment": "node",
+  "testPathIgnorePatterns": ['/node_modules/', '.js$'],
+  "moduleFileExtensions": [
+    "ts",
+    "tsx",
+    "js",
+    "jsx",
+    "json",
+    "node"
+  ]
+}
\ No newline at end of file
diff --git a/knip.ts b/knip.ts
new file mode 100644
index 000000000..4894f6ad5
--- /dev/null
+++ b/knip.ts
@@ -0,0 +1,11 @@
+import type { KnipConfig } from "knip";
+
+const config: KnipConfig = {
+  entry: ["src/index.ts"],
+  project: ["src/**/*.ts"],
+  ignore: ["src/types/config.ts"],
+  ignoreExportsUsedInFile: true,
+  ignoreDependencies: [],
+};
+
+export default config;
diff --git a/netlify.toml b/netlify.toml
index f77808e97..d30333d7d 100644
--- a/netlify.toml
+++ b/netlify.toml
@@ -1,6 +1,15 @@
 [Settings]
 ID = "d2668848-c2a6-411f-b884-004faee1942f"
+
 [build]
-functions = "./.netlify/functions"
-# Specify is-core-module/package.json as an external dependency
-ignore = "is-core-module/package.json"
\ No newline at end of file
+  command = "echo \"export const COMMIT_HASH = '$COMMIT_REF';\" > src/commit-hash.ts && bun tsc"
+  functions = "./.netlify/functions"
+  publish = "dist"
+
+[build.environment]
+  NODE_OPTIONS = "--enable-source-maps"
+
+[[headers]]
+  for = "*.js.map"
+  [headers.values]
+    Access-Control-Allow-Origin = "*"
\ No newline at end of file
diff --git a/package.json b/package.json
index 3f9884a9e..e40bcfa49 100644
--- a/package.json
+++ b/package.json
@@ -11,85 +11,87 @@
     "probot-app"
   ],
   "scripts": {
-    "build:ci": "ncc build src/adapters/github/github-actions.ts -o ./",
-    "build:serverless": "ncc build src/index.ts -o ./",
-    "build": "tsc",
-    "postbuild": "copyfiles src/assets/images/* lib/",
-    "clean": "rimraf ./dist ./lib ./node_modules",
-    "format:check": "prettier -c src/**/*.ts",
-    "format": "prettier --write src",
-    "lint": "eslint --ext .ts ./src",
-    "start:serverless": "tsx src/adapters/github/github-actions.ts",
-    "start:watch": "nodemon --exec 'yarn start'",
-    "utils:cspell": "cspell --config .cspell.json 'src/**/*.{js,ts,json,md,yml}'",
-    "start": "probot run ./lib/index.js",
-    "prepare": "husky install"
+    "inspect": "node --inspect node_modules/.bin/probot run ./dist/main.js",
+    "clean": "rimraf ./dist ./node_modules",
+    "format": "run-s format:prettier format:eslint format:cspell",
+    "format:prettier": "prettier --write src",
+    "format:eslint": "eslint --fix --ext .ts ./src",
+    "format:cspell": "cspell --config .cspell.json 'src/**/*.{js,ts,json,md,yml}'",
+    "start:watch": "nodemon --exec 'bun start'",
+    "start": "probot run ./dist/main.js",
+    "format:knip": "knip",
+    "format:knip-ci": "knip --no-exit-code --reporter json",
+    "prepare": "husky install",
+    "test": "jest",
+    "logs:netlify": "bun netlify logs:function webhooks"
   },
   "dependencies": {
-    "@actions/core": "^1.10.0",
     "@commitlint/cli": "^17.4.3",
     "@commitlint/config-conventional": "^17.4.3",
-    "@netlify/functions": "^1.4.0",
-    "@probot/adapter-aws-lambda-serverless": "^3.0.2",
+    "@netlify/functions": "^2.4.0",
+    "@octokit/rest": "^20.0.2",
+    "@openzeppelin/contracts": "^5.0.0",
     "@probot/adapter-github-actions": "^3.1.3",
-    "@sinclair/typebox": "^0.31.5",
+    "@sinclair/typebox": "^0.31.22",
     "@supabase/supabase-js": "^2.4.0",
     "@types/ms": "^0.7.31",
-    "@types/parse5": "^7.0.0",
     "@typescript-eslint/eslint-plugin": "^5.59.11",
     "@typescript-eslint/parser": "^5.59.11",
+    "@typescript-eslint/typescript-estree": "^7.0.1",
     "@uniswap/permit2-sdk": "^1.2.0",
     "@vercel/ncc": "^0.34.0",
-    "ajv": "^8.11.2",
+    "ajv": "^8.12.0",
     "ajv-formats": "^2.1.1",
     "axios": "^1.3.2",
-    "copyfiles": "^2.4.1",
     "cspell": "^7.0.0",
     "decimal.js": "^10.4.3",
     "ethers": "^5.7.2",
-    "exponential-backoff": "^3.1.1",
     "husky": "^8.0.2",
-    "jimp": "^0.22.4",
-    "js-yaml": "^4.1.0",
-    "jsonwebtoken": "^9.0.2",
+    "js-tiktoken": "^1.0.7",
+    "jsdom": "^22.1.0",
     "libsodium-wrappers": "^0.7.11",
     "lint-staged": "^13.1.0",
     "lodash": "^4.17.21",
+    "markdown-it": "^13.0.2",
     "ms": "^2.1.3",
     "node-html-parser": "^6.1.5",
-    "node-html-to-image": "^3.3.0",
     "nodemon": "^2.0.19",
+    "npm-run-all": "^4.1.5",
     "openai": "^4.2.0",
-    "parse5": "^7.1.2",
     "prettier": "^2.7.1",
     "probot": "^12.2.4",
-    "telegraf": "^4.11.2",
+    "smee-client": "^2.0.0",
     "tsx": "^3.12.7",
-    "yaml": "^2.2.2"
+    "ubiquibot-logger": "^0.3.5",
+    "yaml": "^2.2.2",
+    "zlib": "^1.0.5"
   },
   "devDependencies": {
+    "@types/dotenv": "^8.2.0",
     "@types/eslint": "^8.40.2",
-    "@types/jest": "^28.1.0",
+    "@types/jest": "^29.5.11",
+    "@types/jsdom": "^21.1.4",
     "@types/libsodium-wrappers": "^0.7.10",
-    "@types/lodash": "^4.14.197",
-    "@types/node": "^14.18.37",
+    "@types/lodash": "^4.14.202",
+    "@types/markdown-it": "^13.0.4",
+    "@types/node": "^18.0.0",
     "@types/source-map-support": "^0.5.6",
     "eslint": "^8.43.0",
-    "jest": "^26.6.3",
-    "nock": "^13.0.5",
+    "jest": "^29.6.2",
+    "knip": "^3.7.1",
+    "octokit": "^3.1.2",
     "rimraf": "3.0.2",
-    "smee-client": "^1.2.2",
     "source-map-support": "^0.5.21",
-    "supabase": "^1.38.1",
-    "ts-jest": "^26.4.4",
-    "typescript": "^4.9.5"
+    "ts-jest": "^29.1.1",
+    "typescript": "^5.0.4"
   },
   "engines": {
     "node": ">=20.10.0"
   },
   "lint-staged": {
-    "*.{ts,json}": [
-      "prettier --write"
+    "*.ts": [
+      "prettier --write",
+      "eslint --fix"
     ],
     "src/**.{ts,json}": [
       "cspell"
@@ -105,6 +107,7 @@
     },
     "verbose": true,
     "ext": "ts",
-    "exec": "yarn start"
-  }
-}
+    "exec": "bun start"
+  },
+  "packageManager": "bun@1.0.23"
+}
\ No newline at end of file
diff --git a/src/adapters/adapters.ts b/src/adapters/adapters.ts
new file mode 100644
index 000000000..a0ccb9592
--- /dev/null
+++ b/src/adapters/adapters.ts
@@ -0,0 +1,32 @@
+import { createClient } from "@supabase/supabase-js";
+import { Access } from "./supabase/helpers/tables/access";
+import { Label } from "./supabase/helpers/tables/label";
+import { Locations } from "./supabase/helpers/tables/locations";
+import { Logs } from "ubiquibot-logger";
+import { Settlement } from "./supabase/helpers/tables/settlement";
+import { Super } from "./supabase/helpers/tables/super";
+import { User } from "./supabase/helpers/tables/user";
+import { Wallet } from "./supabase/helpers/tables/wallet";
+
+import { env } from "../bindings/env";
+import { Database } from "./supabase/types/database";
+
+export const supabaseClient = createClient(env.SUPABASE_URL, env.SUPABASE_KEY, {
+  auth: { persistSession: false },
+});
+
+export function createAdapters() {
+  return {
+    supabase: {
+      access: new Access(supabaseClient),
+      wallet: new Wallet(supabaseClient),
+      user: new User(supabaseClient),
+      debit: new Settlement(supabaseClient),
+      settlement: new Settlement(supabaseClient),
+      label: new Label(supabaseClient),
+      logs: new Logs(supabaseClient, env.LOG_RETRY_LIMIT, env.LOG_LEVEL, null),
+      locations: new Locations(supabaseClient),
+      super: new Super(supabaseClient),
+    },
+  };
+}
diff --git a/src/adapters/github/github-actions.ts b/src/adapters/github/github-actions.ts
index 6ec7c72a4..a6e74c779 100644
--- a/src/adapters/github/github-actions.ts
+++ b/src/adapters/github/github-actions.ts
@@ -1,5 +1,5 @@
 import probot from "@probot/adapter-github-actions";
-import main from "../../index";
+import main from "../../main";
 
 probot.run(main).catch((error: Error) => {
   console.error(`Error happening... name: ${error.name}, message: ${error.message}`);
diff --git a/src/adapters/index.ts b/src/adapters/index.ts
deleted file mode 100644
index 5279a354a..000000000
--- a/src/adapters/index.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { Telegraf } from "telegraf";
-import { BotConfig } from "../types";
-import { Adapters } from "../types/adapters";
-import { supabase } from "./supabase";
-export * from "./telegram";
-
-export const createAdapters = (config: BotConfig): Adapters => {
-  return {
-    supabase: supabase(config?.supabase?.url ?? process.env.SUPABASE_URL, config?.supabase?.key ?? process.env.SUPABASE_KEY),
-    telegram: new Telegraf(config?.telegram?.token ?? process.env.TELEGRAM_BOT_TOKEN).telegram,
-  };
-};
diff --git a/src/adapters/supabase/helpers/client.ts b/src/adapters/supabase/helpers/client.ts
index b8a3b23da..a23e54cae 100644
--- a/src/adapters/supabase/helpers/client.ts
+++ b/src/adapters/supabase/helpers/client.ts
@@ -1,575 +1,11 @@
-import { createClient, SupabaseClient } from "@supabase/supabase-js";
-import { getAdapters, getLogger } from "../../../bindings";
-import { Issue, UserProfile } from "../../../types";
-import { Database } from "../types";
-import { InsertPermit, Permit } from "../../../helpers";
-import { BigNumber, BigNumberish } from "ethers";
+import { Database } from "../types/database";
 
-interface AccessLevels {
-  multiplier: boolean;
-  price: boolean;
-  priority: boolean;
-  time: boolean;
-}
-
-/**
- * @dev Creates a typescript client which will be used to interact with supabase platform
- *
- * @param url - The supabase project url
- * @param key - The supabase project key
- * @returns - The supabase client
- */
-export const supabase = (url: string, key: string): SupabaseClient => {
-  return createClient(url, key, { auth: { persistSession: false } });
-};
-
-/**
- * @dev Gets the maximum issue number stored in `issues` table
- */
-export const getMaxIssueNumber = async (): Promise => {
-  const { supabase } = getAdapters();
-
-  const { data } = await supabase.from("issues").select("issue_number").order("issue_number", { ascending: false }).limit(1).single();
-  if (data) {
-    return Number(data.issue_number);
-  } else {
-    return 0;
-  }
-};
-
-/**
- * @dev Gets the last weekly update timestamp
- */
-export const getLastWeeklyTime = async (): Promise => {
-  const { supabase } = getAdapters();
-
-  const { data } = await supabase.from("weekly").select("last_time").limit(1).single();
-  if (data) {
-    return new Date(data.last_time);
-  } else {
-    return undefined;
-  }
-};
-
-/**
- * @dev Updates the last weekly update timestamp
- */
-export const updateLastWeeklyTime = async (time: Date): Promise => {
-  const logger = getLogger();
-  const { supabase } = getAdapters();
-
-  const { data, error } = await supabase.from("weekly").select("last_time");
-  if (error) {
-    logger.error(`Checking last time failed, error: ${JSON.stringify(error)}`);
-    throw new Error(`Checking last time failed, error: ${JSON.stringify(error)}`);
-  }
-
-  if (data && data.length > 0) {
-    const { data, error } = await supabase.from("weekly").update({ last_time: time.toUTCString() }).neq("last_time", time.toUTCString());
-    if (error) {
-      logger.error(`Updating last time failed, error: ${JSON.stringify(error)}`);
-      throw new Error(`Updating last time failed, error: ${JSON.stringify(error)}`);
-    }
-    logger.info(`Updating last time is done, data: ${data}`);
-  } else {
-    const { data, error } = await supabase.from("weekly").insert({ last_time: time.toUTCString() });
-    if (error) {
-      logger.error(`Creating last time failed, error: ${JSON.stringify(error)}`);
-      throw new Error(`Creating last time failed, error: ${JSON.stringify(error)}`);
-    }
-    logger.info(`Creating last time is done, data: ${data}`);
-  }
-  return;
-};
-
-export type IssueAdditions = {
-  labels: {
-    timeline: string;
-    priority: string;
-    price: string;
-  };
-
-  started_at?: number;
-  completed_at?: number;
-};
-
-const getDbDataFromIssue = (issue: Issue, additions: IssueAdditions) => {
-  return {
-    issue_number: issue.number,
-    issue_url: issue.html_url,
-    comments_url: issue.comments_url,
-    events_url: issue.events_url,
-    labels: issue.labels.map((issue) => issue.name),
-    assignees: issue.assignees ? issue.assignees.map((assignee) => assignee.login) : [],
-    timeline: additions.labels.timeline,
-    priority: additions.labels.priority,
-    price: additions.labels.price,
-    started_at: additions.started_at,
-    completed_at: additions.completed_at,
-    closed_at: issue.closed_at,
-    created_at: issue.created_at,
-    updated_at: issue.updated_at,
-  };
-};
-
-export type UserProfileAdditions = {
-  wallet_address?: string;
-};
-const getDbDataFromUserProfile = (userProfile: UserProfile, additions?: UserProfileAdditions) => {
-  return {
-    user_login: userProfile.login,
-    user_type: userProfile.type,
-    user_name: userProfile.name ?? userProfile.login,
-    company: userProfile.company,
-    blog: userProfile.blog,
-    user_location: userProfile.location,
-    email: userProfile.email,
-    bio: userProfile.bio,
-    twitter_username: userProfile.twitter_username,
-    public_repos: userProfile.public_repos,
-    followers: userProfile.followers,
-    following: userProfile.following,
-    wallet_address: additions?.wallet_address,
-    created_at: userProfile.created_at,
-    updated_at: userProfile.updated_at,
-  };
-};
-/**
- * Performs an UPSERT on the issues table.
- * @param issue The issue entity fetched from github event.
- */
-export const upsertIssue = async (issue: Issue, additions: IssueAdditions): Promise => {
-  const logger = getLogger();
-  const { supabase } = getAdapters();
-  const { data, error } = await supabase.from("issues").select("id").eq("issue_number", issue.number);
-  if (error) {
-    logger.error(`Checking issue failed, error: ${JSON.stringify(error)}`);
-    throw new Error(`Checking issue failed, error: ${JSON.stringify(error)}`);
-  }
-
-  if (data && data.length > 0) {
-    const key = data[0].id as number;
-    const { data: _data, error: _error } = await supabase
-      .from("issues")
-      .upsert({ id: key, ...getDbDataFromIssue(issue, additions) })
-      .select();
-    if (_error) {
-      logger.error(`Upserting an issue failed, error: ${JSON.stringify(_error)}`);
-      throw new Error(`Upserting an issue failed, error: ${JSON.stringify(_error)}`);
-    }
-    logger.info(`Upserting an issue done, { data: ${_data}, error: ${_error}`);
-  } else {
-    const { data: _data, error: _error } = await supabase.from("issues").insert(getDbDataFromIssue(issue, additions));
-    if (_error) {
-      logger.error(`Creating a new issue record failed, error: ${JSON.stringify(_error)}`);
-      throw new Error(`Creating a new issue record failed, error: ${JSON.stringify(_error)}`);
-    }
-    logger.info(`Creating a new issue record done, { data: ${_data}, error: ${_error}`);
-  }
-};
-
-/**
- * Performs an UPSERT on the users table.
- * @param user The user entity fetched from github event.
- */
-export const upsertUser = async (user: UserProfile): Promise => {
-  const logger = getLogger();
-  const { supabase } = getAdapters();
-  const { data, error } = await supabase.from("users").select("user_login").eq("user_login", user.login);
-  if (error) {
-    logger.error(`Checking user failed, error: ${JSON.stringify(error)}`);
-    throw new Error(`Checking user failed, error: ${JSON.stringify(error)}`);
-  }
-
-  if (data && data.length > 0) {
-    const { data: _data, error: _error } = await supabase.from("users").upsert(getDbDataFromUserProfile(user)).select();
-    if (_error) {
-      logger.error(`Upserting a user failed, error: ${JSON.stringify(_error)}`);
-      throw new Error(`Upserting a user failed, error: ${JSON.stringify(_error)}`);
-    }
-    logger.info(`Upserting a user done, { data: ${JSON.stringify(_data)} }`);
-  } else {
-    const { data: _data, error: _error } = await supabase.from("users").insert(getDbDataFromUserProfile(user));
-    if (_error) {
-      logger.error(`Creating a new user record failed, error: ${JSON.stringify(_error)}`);
-      throw new Error(`Creating a new user record failed, error: ${JSON.stringify(_error)}`);
-    }
-    logger.info(`Creating a new user record done, { data: ${JSON.stringify(_data)} }`);
-  }
-};
-
-/**
- * Performs an UPSERT on the wallet table.
- * @param username The user name you want to upsert a wallet address for
- * @param address The account address
- */
-export const upsertWalletAddress = async (username: string, address: string): Promise => {
-  const logger = getLogger();
-  const { supabase } = getAdapters();
-
-  const { data, error } = await supabase.from("wallets").select("user_name").eq("user_name", username);
-  if (error) {
-    logger.error(`Checking wallet address failed, error: ${JSON.stringify(error)}`);
-    throw new Error(`Checking wallet address failed, error: ${JSON.stringify(error)}`);
-  }
-
-  if (data && data.length > 0) {
-    const { data: _data, error: _error } = await supabase.from("wallets").upsert({
-      user_name: username,
-      wallet_address: address,
-      updated_at: new Date().toUTCString(),
-    });
-    if (_error) {
-      logger.error(`Upserting a wallet address failed, error: ${JSON.stringify(_error)}`);
-      throw new Error(`Upserting a wallet address failed, error: ${JSON.stringify(_error)}`);
-    }
-    logger.info(`Upserting a wallet address done, { data: ${JSON.stringify(_data)} }`);
-  } else {
-    const { error } = await supabase.from("wallets").insert({
-      user_name: username,
-      wallet_address: address,
-      created_at: new Date().toUTCString(),
-      updated_at: new Date().toUTCString(),
-    });
-    if (error) {
-      logger.error(`Creating a new wallet_table record failed, error: ${JSON.stringify(error)}`);
-      throw new Error(`Creating a new wallet_table record failed, error: ${JSON.stringify(error)}`);
-    }
-    logger.info(`Creating a new wallet_table record done, { data: ${JSON.stringify(data)}, address: $address }`);
-  }
-};
-
-/**
- * Performs an UPSERT on the multiplier table.
- * @param username The user name you want to upsert a wallet address for
- * @param address The account multiplier
- */
-export const upsertWalletMultiplier = async (username: string, multiplier: string, reason: string, org_id: string): Promise => {
-  const logger = getLogger();
-  const { supabase } = getAdapters();
-
-  const { data, error } = await supabase.from("multiplier").select("user_id").eq("user_id", `${username}_${org_id}`);
-  if (error) {
-    logger.error(`Checking wallet multiplier failed, error: ${JSON.stringify(error)}`);
-    throw new Error(`Checking wallet multiplier failed, error: ${JSON.stringify(error)}`);
-  }
-
-  if (data && data.length > 0) {
-    const { data: _data, error: _error } = await supabase.from("multiplier").upsert({
-      user_id: `${username}_${org_id}`,
-      value: multiplier,
-      reason,
-      updated_at: new Date().toUTCString(),
-    });
-    if (_error) {
-      logger.error(`Upserting a wallet multiplier failed, error: ${JSON.stringify(_error)}`);
-      throw new Error(`Upserting a wallet multiplier failed, error: ${JSON.stringify(_error)}`);
-    }
-    logger.info(`Upserting a wallet multiplier done, { data: ${JSON.stringify(_data)} }`);
-  } else {
-    const { data: _data, error: _error } = await supabase.from("multiplier").insert({
-      user_id: `${username}_${org_id}`,
-      value: multiplier,
-      reason,
-      created_at: new Date().toUTCString(),
-      updated_at: new Date().toUTCString(),
-    });
-    if (_error) {
-      logger.error(`Creating a new multiplier record failed, error: ${JSON.stringify(_error)}`);
-      throw new Error(`Creating a new multiplier record failed, error: ${JSON.stringify(_error)}`);
-    }
-    logger.info(`Creating a new multiplier record done, { data: ${JSON.stringify(_data)} }`);
-  }
-};
-
-/**
- * Performs an UPSERT on the access table.
- * @param username The user name you want to upsert a wallet address for
- * @param repository The repository for access
- * @param access Access granting
- * @param bool Disabling or enabling
- */
-export const upsertAccessControl = async (username: string, repository: string, access: string, bool: boolean): Promise => {
-  const logger = getLogger();
-  const { supabase } = getAdapters();
-
-  const { data, error } = await supabase.from("access").select("user_name").eq("user_name", username).eq("repository", repository);
-  if (error) {
-    logger.error(`Checking access control failed, error: ${JSON.stringify(error)}`);
-    throw new Error(`Checking access control failed, error: ${JSON.stringify(error)}`);
-  }
-
-  const properties = {
-    user_name: username,
-    repository: repository,
-    updated_at: new Date().toUTCString(),
-    [access]: bool,
-  };
-
-  if (data && data.length > 0) {
-    const { data: _data, error: _error } = await supabase.from("access").upsert(properties);
-    if (_error) {
-      logger.error(`Upserting a access control failed, error: ${JSON.stringify(_error)}`);
-      throw new Error(`Upserting a access control failed, error: ${JSON.stringify(_error)}`);
-    }
-    logger.info(`Upserting a access control done, { data: ${JSON.stringify(_data)} }`);
-  } else {
-    const { data: _data, error: _error } = await supabase.from("access").insert({
-      created_at: new Date().toUTCString(),
-      price_access: false,
-      time_access: true,
-      multiplier_access: false,
-      priority_access: false,
-      ...properties,
-    });
-    if (_error) {
-      logger.error(`Creating a new access control record failed, error: ${JSON.stringify(_error)}`);
-      throw new Error(`Creating a new access control record failed, error: ${JSON.stringify(_error)}`);
-    }
-    logger.info(`Creating a new access control record done, { data: ${JSON.stringify(_data)} }`);
-  }
-};
-
-export const getAccessLevel = async (username: string, repository: string, label_type: string): Promise => {
-  const logger = getLogger();
-  const { supabase } = getAdapters();
-
-  const { data } = await supabase.from("access").select("*").eq("user_name", username).eq("repository", repository).single();
-
-  if (!data || !data[`${label_type}_access`]) {
-    logger.info(`Access not found on the database`);
-    // no access
-    return false;
-  }
-
-  const accessValues = data[`${label_type}_access`];
-
-  return accessValues;
-};
-
-export const getAllAccessLevels = async (username: string, repository: string): Promise => {
-  const logger = getLogger();
-  const { supabase } = getAdapters();
-
-  const { data } = await supabase.from("access").select("*").eq("user_name", username).eq("repository", repository).single();
-
-  if (!data) {
-    logger.info(`Access not found on the database`);
-    // no access
-    return null;
-  }
-  return { multiplier: data.multiplier_access, time: data.time_access, priority: data.priority_access, price: data.price_access };
-};
-
-/**
- * Queries the wallet address registered previously
- *
- * @param username The username you want to find an address for
- * @returns The ERC20 address
- */
-export const getWalletAddress = async (username: string): Promise => {
-  const { supabase } = getAdapters();
-
-  const { data } = await supabase.from("wallets").select("wallet_address").eq("user_name", username).single();
-  return data?.wallet_address;
-};
-
-/**
- * Queries the wallet multiplier registered previously
- *
- * @param username The username you want to find an address for
- * @returns The Multiplier, returns 1 if not found
- *
- */
-
-export const getWalletMultiplier = async (username: string, org_id: string): Promise<{ value: number; reason: string }> => {
-  const { supabase } = getAdapters();
-
-  const { data } = await supabase.from("multiplier").select("value, reason").eq("user_id", `${username}_${org_id}`).single();
-  if (data?.value == null) return { value: 1, reason: "" };
-  else return { value: data?.value, reason: data?.reason };
-};
-
-/**
- * Queries both the wallet multiplier and address in one request registered previously
- *
- * @param username The username you want to find an address for
- * @returns The Multiplier and ERC-20 Address, returns 1 if not found
- *
- */
-
-export const getWalletInfo = async (username: string, org_id: string): Promise<{ multiplier: number | null; address: string | null }> => {
-  const { supabase } = getAdapters();
-
-  const { data: wallet } = await supabase.from("wallets").select("wallet_address").eq("user_name", username).single();
-  const { data: multiplier } = await supabase.from("multiplier").select("value").eq("user_id", `${username}_${org_id}`).single();
-  if (multiplier?.value == null) {
-    return { multiplier: 1, address: wallet?.wallet_address || "" };
-  } else return { multiplier: multiplier?.value, address: wallet?.wallet_address };
-};
-
-export const addPenalty = async (username: string, repoName: string, tokenAddress: string, networkId: string, penalty: BigNumberish): Promise => {
-  const { supabase } = getAdapters();
-  const logger = getLogger();
-
-  const { error } = await supabase.rpc("add_penalty", {
-    _username: username,
-    _repository_name: repoName,
-    _token_address: tokenAddress,
-    _network_id: networkId,
-    _penalty_amount: penalty.toString(),
-  });
-  logger.debug(`Adding penalty done, { data: ${JSON.stringify(error)}, error: ${JSON.stringify(error)} }`);
-
-  if (error) {
-    throw new Error(`Error adding penalty: ${error.message}`);
-  }
-};
-
-export const getPenalty = async (username: string, repoName: string, tokenAddress: string, networkId: string): Promise => {
-  const { supabase } = getAdapters();
-  const logger = getLogger();
-
-  const { data, error } = await supabase
-    .from("penalty")
-    .select("amount")
-    .eq("username", username)
-    .eq("repository_name", repoName)
-    .eq("network_id", networkId)
-    .eq("token_address", tokenAddress);
-  logger.debug(`Getting penalty done, { data: ${JSON.stringify(error)}, error: ${JSON.stringify(error)} }`);
-
-  if (error) {
-    throw new Error(`Error getting penalty: ${error.message}`);
-  }
-
-  if (data.length === 0) {
-    return BigNumber.from(0);
-  }
-  return BigNumber.from(data[0].amount);
-};
-
-export const removePenalty = async (username: string, repoName: string, tokenAddress: string, networkId: string, penalty: BigNumberish): Promise => {
-  const { supabase } = getAdapters();
-  const logger = getLogger();
-
-  const { error } = await supabase.rpc("remove_penalty", {
-    _username: username,
-    _repository_name: repoName,
-    _network_id: networkId,
-    _token_address: tokenAddress,
-    _penalty_amount: penalty.toString(),
-  });
-  logger.debug(`Removing penalty done, { data: ${JSON.stringify(error)}, error: ${JSON.stringify(error)} }`);
-
-  if (error) {
-    throw new Error(`Error removing penalty: ${error.message}`);
-  }
-};
-
-const getDbDataFromPermit = (permit: InsertPermit): Record => {
-  return {
-    organization_id: permit.organizationId,
-    repository_id: permit.repositoryId,
-    issue_id: permit.issueId,
-    network_id: permit.networkId,
-    bounty_hunter_id: permit.bountyHunterId,
-    token_address: permit.tokenAddress,
-    payout_amount: permit.payoutAmount,
-    bounty_hunter_address: permit.bountyHunterAddress,
-    nonce: permit.nonce,
-    deadline: permit.deadline,
-    signature: permit.signature,
-    wallet_owner_address: permit.walletOwnerAddress,
-  };
-};
-
-const getPermitFromDbData = (data: Record): Permit => {
-  return {
-    id: data.id,
-    createdAt: new Date(Date.parse(data.created_at as string)),
-    organizationId: data.organization_id,
-    repositoryId: data.repository_i,
-    issueId: data.issue_id,
-    networkId: data.network_id,
-    bountyHunterId: data.bounty_hunter_id,
-    tokenAddress: data.token_address,
-    payoutAmount: data.payout_amount,
-    bountyHunterAddress: data.bounty_hunter_address,
-    nonce: data.nonce,
-    deadline: data.deadline,
-    signature: data.signature,
-    walletOwnerAddress: data.wallet_owner_address,
-  } as Permit;
-};
-
-export const savePermit = async (permit: InsertPermit): Promise => {
-  const { supabase } = getAdapters();
-  const { data, error } = await supabase
-    .from("permits")
-    .insert({
-      ...getDbDataFromPermit(permit),
-      created_at: new Date().toISOString(),
-      id: undefined, // id is auto-generated
-    })
-    .select();
-  if (error) {
-    throw new Error(error.message);
-  }
-  if (!data || data.length === 0) {
-    throw new Error("No data returned");
-  }
-  return getPermitFromDbData(data[0]);
+export type GitHubNode = {
+  // will leave support for id and type until more research is completed to confirm that it can be removed
+  node_id?: string;
+  node_type?: GitHubNodeType;
+  // use HTML URL so that administrators can easily audit the location of the node
+  node_url: string;
 };
 
-export const saveLabelChange = async (username: string, repository: string, label_from: string, label_to: string, hasAccess: boolean) => {
-  const { supabase } = getAdapters();
-  const { data, error } = await supabase
-    .from("label_changes")
-    .insert({
-      username,
-      repository,
-      label_from,
-      label_to,
-      authorized: hasAccess || false,
-      created: new Date().toISOString(),
-      updated: new Date().toISOString(),
-    })
-    .select();
-  if (error) {
-    throw new Error(error.message);
-  }
-  if (!data || data.length === 0) {
-    throw new Error("No data returned");
-  }
-  return data[0];
-};
-
-export const getLabelChanges = async (repository: string, labels: string[]) => {
-  const { supabase } = getAdapters();
-  const logger = getLogger();
-
-  const { data, error } = await supabase.from("label_changes").select("*").in("label_to", labels).eq("repository", repository).eq("authorized", false);
-
-  logger.debug(`Getting label changes done, { data: ${JSON.stringify(data)}, error: ${JSON.stringify(error)} }`);
-
-  if (error) {
-    throw new Error(`Error getting label changes: ${error.message}`);
-  }
-
-  if (data.length === 0) {
-    return null;
-  }
-  return data[0];
-};
-
-export const _approveLabelChange = async (changeId: number) => {
-  const { supabase } = getAdapters();
-  const { error } = await supabase.from("label_changes").update({ authorized: true }).eq("id", changeId);
-
-  if (error) {
-    throw new Error(error.message);
-  }
-
-  return;
-};
+type GitHubNodeType = Database["public"]["Enums"]["github_node_type"]; // Manually searched for every type that supports `url`
diff --git a/src/adapters/supabase/helpers/index.ts b/src/adapters/supabase/helpers/index.ts
deleted file mode 100644
index 3bb7e5e98..000000000
--- a/src/adapters/supabase/helpers/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from "./client";
-export * from "./log";
diff --git a/src/adapters/supabase/helpers/log.ts b/src/adapters/supabase/helpers/log.ts
deleted file mode 100644
index 81bbf9d6b..000000000
--- a/src/adapters/supabase/helpers/log.ts
+++ /dev/null
@@ -1,281 +0,0 @@
-import axios from "axios";
-import { getAdapters, getBotContext, Logger } from "../../../bindings";
-import { Payload, LogLevel, LogNotification } from "../../../types";
-import { getOrgAndRepoFromPath } from "../../../utils/private";
-import jwt from "jsonwebtoken";
-interface Log {
-  repo: string | null;
-  org: string | null;
-  commentId: number | undefined;
-  issueNumber: number | undefined;
-  logMessage: string;
-  level: LogLevel;
-  timestamp: string;
-}
-
-export const getNumericLevel = (level: LogLevel) => {
-  switch (level) {
-    case LogLevel.ERROR:
-      return 0;
-    case LogLevel.WARN:
-      return 1;
-    case LogLevel.INFO:
-      return 2;
-    case LogLevel.HTTP:
-      return 3;
-    case LogLevel.VERBOSE:
-      return 4;
-    case LogLevel.DEBUG:
-      return 5;
-    case LogLevel.SILLY:
-      return 6;
-    default:
-      return -1; // Invalid level
-  }
-};
-
-export class GitHubLogger implements Logger {
-  private supabase;
-  private maxLevel;
-  private app;
-  private logEnvironment;
-  private logQueue: Log[] = []; // Your log queue
-  private maxConcurrency = 6; // Maximum concurrent requests
-  private retryDelay = 1000; // Delay between retries in milliseconds
-  private throttleCount = 0;
-  private retryLimit = 0; // Retries disabled by default
-  private logNotification;
-
-  constructor(app: string, logEnvironment: string, maxLevel: LogLevel, retryLimit: number, logNotification: LogNotification) {
-    this.app = app;
-    this.logEnvironment = logEnvironment;
-    this.maxLevel = getNumericLevel(maxLevel);
-    this.retryLimit = retryLimit;
-    this.supabase = getAdapters().supabase;
-    this.logNotification = logNotification;
-  }
-
-  async sendLogsToSupabase({ repo, org, commentId, issueNumber, logMessage, level, timestamp }: Log) {
-    const { error } = await this.supabase.from("logs").insert([
-      {
-        repo_name: repo,
-        level: getNumericLevel(level),
-        org_name: org,
-        comment_id: commentId,
-        log_message: logMessage,
-        issue_number: issueNumber,
-        timestamp,
-      },
-    ]);
-
-    if (error) {
-      console.error("Error logging to Supabase:", error.message);
-      return;
-    }
-  }
-
-  async processLogs(log: Log) {
-    try {
-      await this.sendLogsToSupabase(log);
-    } catch (error) {
-      console.error("Error sending log, retrying:", error);
-      return this.retryLimit > 0 ? await this.retryLog(log) : null;
-    }
-  }
-
-  private sendDataWithJwt(message: string | object, errorPayload?: string | object) {
-    const context = getBotContext();
-    const payload = context.payload as Payload;
-
-    const { comment, issue, repository } = payload;
-    const commentId = comment?.id;
-    const issueNumber = issue?.number;
-    const repoFullName = repository?.full_name;
-
-    const { org, repo } = getOrgAndRepoFromPath(repoFullName);
-
-    const issueLink = `https://github.com/${org}/${repo}/issues/${issueNumber}${commentId ? `#issuecomment-${commentId}` : ""}`;
-
-    return new Promise((resolve, reject) => {
-      try {
-        if (!this.logNotification?.enabled) {
-          reject("Telegram Log Notification is disabled, please check that url, secret and group is provided");
-        }
-
-        if (typeof message === "object") {
-          message = JSON.stringify(message);
-        }
-
-        if (errorPayload && typeof errorPayload === "object") {
-          errorPayload = JSON.stringify(errorPayload);
-        }
-
-        const errorMessage = `\`${message}${errorPayload ? " - " + errorPayload : ""}\`\n\nContext: ${issueLink}`;
-
-        // Step 1: Sign a JWT with the provided parameter
-        const jwtToken = jwt.sign(
-          {
-            group: this.logNotification.groupId,
-            topic: this.logNotification.topicId,
-            msg: errorMessage,
-          },
-          this.logNotification.secret,
-          { noTimestamp: true }
-        );
-
-        const apiUrl = `${this.logNotification.url}/sendLogs`;
-        const headers = {
-          Authorization: `${jwtToken}`,
-        };
-
-        axios
-          .get(apiUrl, { headers })
-          .then((response) => {
-            resolve(response.data);
-          })
-          .catch((error) => {
-            reject(error);
-          });
-      } catch (error) {
-        // Reject the promise with the error
-        reject(error);
-      }
-    });
-  }
-
-  async retryLog(log: Log, retryCount = 0) {
-    if (retryCount >= this.retryLimit) {
-      console.error("Max retry limit reached for log:", log);
-      return;
-    }
-
-    await new Promise((resolve) => setTimeout(resolve, this.retryDelay));
-
-    try {
-      await this.sendLogsToSupabase(log);
-    } catch (error) {
-      console.error("Error sending log (after retry):", error);
-      await this.retryLog(log, retryCount + 1);
-    }
-  }
-
-  async processLogQueue() {
-    while (this.logQueue.length > 0) {
-      const log = this.logQueue.shift();
-      if (!log) {
-        continue;
-      }
-      await this.processLogs(log);
-    }
-  }
-
-  async throttle() {
-    if (this.throttleCount >= this.maxConcurrency) {
-      return;
-    }
-
-    this.throttleCount++;
-    try {
-      await this.processLogQueue();
-    } finally {
-      this.throttleCount--;
-      if (this.logQueue.length > 0) {
-        await this.throttle();
-      }
-    }
-  }
-
-  async addToQueue(log: Log) {
-    this.logQueue.push(log);
-    if (this.throttleCount < this.maxConcurrency) {
-      await this.throttle();
-    }
-  }
-
-  private save(logMessage: string | object, level: LogLevel, errorPayload?: string | object) {
-    if (getNumericLevel(level) > this.maxLevel) return; // only return errors lower than max level
-
-    const context = getBotContext();
-    const payload = context.payload as Payload;
-    const timestamp = new Date().toUTCString();
-
-    const { comment, issue, repository } = payload;
-    const commentId = comment?.id;
-    const issueNumber = issue?.number;
-    const repoFullName = repository?.full_name;
-
-    const { org, repo } = getOrgAndRepoFromPath(repoFullName);
-
-    if (!logMessage) return;
-
-    if (typeof logMessage === "object") {
-      // pass log as json stringified
-      logMessage = JSON.stringify(logMessage);
-    }
-
-    this.addToQueue({ repo, org, commentId, issueNumber, logMessage, level, timestamp })
-      .then(() => {
-        return;
-      })
-      .catch(() => {
-        console.log("Error adding logs to queue");
-      });
-
-    if (this.logEnvironment === "development") {
-      console.log(this.app, logMessage, errorPayload, level, repo, org, commentId, issueNumber);
-    }
-  }
-
-  info(message: string | object, errorPayload?: string | object) {
-    this.save(message, LogLevel.INFO, errorPayload);
-  }
-
-  warn(message: string | object, errorPayload?: string | object) {
-    this.save(message, LogLevel.WARN, errorPayload);
-    this.sendDataWithJwt(message, errorPayload)
-      .then((response) => {
-        this.save(`Log Notification Success: ${response}`, LogLevel.DEBUG, "");
-      })
-      .catch((error) => {
-        this.save(`Log Notification Error: ${error}`, LogLevel.DEBUG, "");
-      });
-  }
-
-  debug(message: string | object, errorPayload?: string | object) {
-    this.save(message, LogLevel.DEBUG, errorPayload);
-  }
-
-  error(message: string | object, errorPayload?: string | object) {
-    this.save(message, LogLevel.ERROR, errorPayload);
-    this.sendDataWithJwt(message, errorPayload)
-      .then((response) => {
-        this.save(`Log Notification Success: ${response}`, LogLevel.DEBUG, "");
-      })
-      .catch((error) => {
-        this.save(`Log Notification Error: ${error}`, LogLevel.DEBUG, "");
-      });
-  }
-
-  async get() {
-    try {
-      const { data, error } = await this.supabase.from("logs").select("*");
-
-      if (error) {
-        console.error("Error retrieving logs from Supabase:", error.message);
-        return [];
-      }
-
-      return data;
-    } catch (error) {
-      if (error instanceof Error) {
-        // 👉️ err is type Error here
-        console.error("An error occurred:", error.message);
-
-        return;
-      }
-
-      console.log("Unexpected error", error);
-      return [];
-    }
-  }
-}
diff --git a/src/adapters/supabase/helpers/tables/access.ts b/src/adapters/supabase/helpers/tables/access.ts
new file mode 100644
index 000000000..3bd7fc630
--- /dev/null
+++ b/src/adapters/supabase/helpers/tables/access.ts
@@ -0,0 +1,74 @@
+import { SupabaseClient } from "@supabase/supabase-js";
+import { GitHubComment } from "../../../../types/payload";
+import { Database } from "../../types/database";
+import { GitHubNode } from "../client";
+import { Super } from "./super";
+import { UserRow } from "./user";
+type AccessRow = Database["public"]["Tables"]["access"]["Row"];
+type AccessInsert = Database["public"]["Tables"]["access"]["Insert"];
+type UserWithAccess = (UserRow & { access: AccessRow | null })[];
+
+type AccessData = {
+  user_id: number;
+  multiplier: number;
+  multiplier_reason: string;
+  node_id: string;
+  node_type: string;
+  node_url: string;
+};
+
+export class Access extends Super {
+  constructor(supabase: SupabaseClient) {
+    super(supabase);
+  }
+
+  private async _getUserWithAccess(id: number): Promise {
+    const { data, error } = await this.supabase.from("access").select("*, users(*)").filter("id", "eq", id);
+
+    if (error) {
+      this.runtime.logger.fatal(error.message, error);
+      throw new Error(error.message);
+    }
+    return data;
+  }
+
+  public async getAccess(id: number): Promise {
+    const userWithAccess = await this._getUserWithAccess(id);
+    if (userWithAccess[0]?.access === undefined) {
+      this.runtime.logger.debug("Access is undefined");
+      return null;
+    }
+    if (userWithAccess[0]?.access === null) throw new Error("Access is null");
+    return userWithAccess[0].access;
+  }
+
+  public async setAccess(labels: string[], node: GitHubNode, userId?: number): Promise {
+    const { data, error } = await this.supabase.from("access").upsert({
+      labels: labels,
+      ...node,
+      user_id: userId,
+    } as AccessInsert);
+    if (error) throw new Error(error.message);
+    return data;
+  }
+
+  async upsertMultiplier(userId: number, multiplier: number, reason: string, comment: GitHubComment) {
+    try {
+      const accessData: AccessData = {
+        user_id: userId,
+        multiplier: multiplier,
+        multiplier_reason: reason,
+        node_id: comment.node_id,
+        node_type: "IssueComment",
+        node_url: comment.html_url,
+      };
+
+      const { data, error } = await this.supabase.from("access").upsert(accessData, { onConflict: "location_id" });
+
+      if (error) throw new Error(error.message);
+      if (!data) throw new Error("Multiplier not upserted");
+    } catch (error) {
+      console.error("An error occurred while upserting multiplier:", error);
+    }
+  }
+}
diff --git a/src/adapters/supabase/helpers/tables/label.ts b/src/adapters/supabase/helpers/tables/label.ts
new file mode 100644
index 000000000..414d6057a
--- /dev/null
+++ b/src/adapters/supabase/helpers/tables/label.ts
@@ -0,0 +1,85 @@
+import { SupabaseClient } from "@supabase/supabase-js";
+import { GitHubRepository } from "../../../../types/payload";
+
+import Runtime from "../../../../bindings/bot-runtime";
+import { Database } from "../../types/database";
+import { Super } from "./super";
+
+type LabelRow = Database["public"]["Tables"]["labels"]["Row"];
+
+export class Label extends Super {
+  constructor(supabase: SupabaseClient) {
+    super(supabase);
+  }
+
+  async saveLabelChange({
+    previousLabel,
+    currentLabel,
+    authorized,
+    repository,
+  }: {
+    previousLabel: string;
+    currentLabel: string;
+    authorized: boolean;
+    repository: GitHubRepository;
+  }): Promise {
+    const { data, error } = await this.supabase.from("labels").insert({
+      label_from: previousLabel,
+      label_to: currentLabel,
+      authorized: authorized,
+      node_id: repository.node_id,
+      node_type: "Repository",
+      node_url: repository.html_url,
+    });
+
+    if (error) throw new Error(error.message);
+    return data;
+  }
+
+  async getLabelChanges(repositoryNodeId: string) {
+    const locationId = await this._getRepositoryLocationId(repositoryNodeId);
+    if (!locationId) {
+      return null;
+    }
+    const unauthorizedLabelChanges = await this._getUnauthorizedLabelChanges(locationId);
+    return unauthorizedLabelChanges;
+  }
+
+  async approveLabelChange(id: number): Promise {
+    const { data, error } = await this.supabase.from("labels").update({ authorized: true }).eq("id", id);
+    if (error) throw new Error(error.message);
+    return data;
+  }
+
+  private async _getUnauthorizedLabelChanges(locationId: number): Promise {
+    // Get label changes that are not authorized in the repository
+    const { data, error } = await this.supabase
+      .from("labels")
+      .select("*")
+      .eq("location_id", locationId)
+      .eq("authorized", false);
+
+    if (error) throw new Error(error.message);
+
+    return data;
+  }
+
+  private async _getRepositoryLocationId(nodeId: string) {
+    const runtime = Runtime.getState();
+    // Get the location_id for the repository from the locations table
+    const { data: locationData, error: locationError } = await this.supabase
+      .from("locations")
+      .select("id")
+      .eq("node_id", nodeId)
+      .maybeSingle();
+
+    if (locationError) throw new Error(locationError.message);
+    if (!locationData) {
+      runtime.logger.error("Repository location ID not found in database.");
+      return null;
+    }
+
+    const locationId = locationData.id;
+    return locationId;
+  }
+}
diff --git a/src/adapters/supabase/helpers/tables/locations.ts b/src/adapters/supabase/helpers/tables/locations.ts
new file mode 100644
index 000000000..c1c7750dc
--- /dev/null
+++ b/src/adapters/supabase/helpers/tables/locations.ts
@@ -0,0 +1,32 @@
+import { SupabaseClient } from "@supabase/supabase-js";
+import { Super } from "./super";
+import { Database } from "../../types/database";
+
+// currently trying to save all of the location metadata of the event.
+// seems that focusing on the IssueComments will provide the most value
+
+type LocationsRow = Database["public"]["Tables"]["logs"]["Row"];
+export class Locations extends Super {
+  locationResponse: LocationsRow | undefined;
+
+  user_id: string | undefined;
+  comment_id: string | undefined;
+  issue_id: string | undefined;
+  repository_id: string | undefined;
+  node_id: string | undefined;
+  node_type: string | undefined;
+
+  constructor(supabase: SupabaseClient) {
+    super(supabase);
+  }
+
+  public async getLocationsFromRepo(repositoryId: number) {
+    const { data: locationData, error } = await this.supabase
+      .from("locations")
+      .select("id")
+      .eq("repository_id", repositoryId);
+
+    if (error) throw this.runtime.logger.fatal("Error getting location data", new Error(error.message));
+    return locationData;
+  }
+}
diff --git a/src/adapters/supabase/helpers/tables/settlement.ts b/src/adapters/supabase/helpers/tables/settlement.ts
new file mode 100644
index 000000000..9e7abf8f2
--- /dev/null
+++ b/src/adapters/supabase/helpers/tables/settlement.ts
@@ -0,0 +1,175 @@
+import { SupabaseClient } from "@supabase/supabase-js";
+import Decimal from "decimal.js";
+import { GitHubComment, GitHubPayload } from "../../../../types/payload";
+import { Database } from "../../types/database";
+import { Super } from "./super";
+
+interface PermitTransactionData {
+  permit: {
+    permitted: {
+      token: string;
+      amount: string;
+    };
+    nonce: string;
+    deadline: string;
+  };
+  transferDetails: {
+    to: string;
+    requestedAmount: string;
+  };
+  owner: string;
+  signature: string;
+}
+
+type DebitInsert = Database["public"]["Tables"]["debits"]["Insert"];
+type CreditInsert = Database["public"]["Tables"]["credits"]["Insert"];
+type PermitInsert = Database["public"]["Tables"]["permits"]["Insert"];
+type SettlementInsert = Database["public"]["Tables"]["settlements"]["Insert"];
+type AddDebit = {
+  userId: number;
+  amount: Decimal;
+  // comment: Comment;
+  networkId: number;
+  address: string;
+};
+type AddCreditWithPermit = {
+  userId: number;
+  amount: Decimal;
+  comment: GitHubComment;
+  transactionData?: PermitTransactionData;
+  networkId?: number;
+  organization?: GitHubPayload["organization"];
+};
+
+export class Settlement extends Super {
+  constructor(supabase: SupabaseClient) {
+    super(supabase);
+  }
+
+  private async _lookupTokenId(networkId: number, address: string): Promise {
+    const { data: tokenData, error: tokenError } = await this.supabase
+      .from("tokens")
+      .select("id")
+      .eq("network", networkId)
+      .eq("address", address)
+      .maybeSingle();
+
+    if (tokenError) throw new Error(tokenError.message);
+    if (!tokenData) throw new Error("Token not found");
+
+    return tokenData.id;
+  }
+
+  public async addDebit({ userId, amount, networkId, address }: AddDebit) {
+    // Lookup the tokenId
+    const tokenId = await this._lookupTokenId(networkId, address);
+
+    // Insert into the debits table
+    const debitData: DebitInsert = {
+      amount: amount.toNumber(),
+      // node_id: comment.node_id,
+      // node_type: "IssueComment",
+      // node_url: comment.html_url,
+      token_id: tokenId,
+    };
+
+    const { data: debitInsertData, error: debitError } = await this.supabase
+      .from("debits")
+      .insert(debitData)
+      .select()
+      .maybeSingle();
+
+    if (debitError) throw new Error(debitError.message);
+    if (!debitInsertData) throw new Error("Debit not inserted");
+
+    // Insert into the settlements table
+    const settlementData: SettlementInsert = {
+      id: debitInsertData.id,
+      debit_id: debitInsertData.id,
+      user_id: userId,
+      location_id: debitInsertData.location_id, // Should be updated by trigger
+    };
+
+    const { data: settlementInsertData, error: settlementError } = await this.supabase
+      .from("settlements")
+      .insert(settlementData)
+      .select()
+      .maybeSingle();
+
+    if (settlementError) throw new Error(settlementError.message);
+    if (!settlementInsertData) throw new Error("Settlement not inserted");
+  }
+
+  public async addCredit({
+    userId,
+    amount,
+    // comment,
+    transactionData,
+    networkId,
+    organization,
+  }: AddCreditWithPermit) {
+    // Insert into the credits table
+    const creditData: CreditInsert = {
+      amount: amount.toNumber(),
+    };
+
+    const { data: creditInsertData, error: creditError } = await this.supabase
+      .from("credits")
+      .insert(creditData)
+      .select()
+      .maybeSingle();
+
+    if (creditError) throw new Error(creditError.message);
+    if (!creditInsertData) throw new Error("Credit not inserted");
+
+    // Insert into the permits table if permit data is provided
+    let permitInsertData;
+    if (transactionData) {
+      if (!organization) throw new Error("Organization not provided");
+      if (!networkId) throw new Error("Network ID not provided");
+
+      const permitData: PermitInsert = {
+        amount: transactionData.permit.permitted.amount,
+        nonce: transactionData.permit.nonce,
+        deadline: transactionData.permit.deadline,
+        signature: transactionData.signature,
+        token_id: await this._lookupTokenId(networkId, transactionData.permit.permitted.token),
+        partner_id: organization.id,
+        beneficiary_id: userId,
+      };
+
+      const permitResult = await this.supabase.from("permits").insert(permitData).select().maybeSingle();
+
+      if (permitResult.error) throw new Error(permitResult.error.message);
+      if (!permitResult.data) throw new Error("Permit not inserted");
+      permitInsertData = permitResult.data;
+    }
+
+    // Update the credits table with permit_id if permit data is provided
+    if (permitInsertData) {
+      const { error: creditUpdateError } = await this.supabase
+        .from("credits")
+        .update({ permit_id: permitInsertData.id })
+        .eq("id", creditInsertData.id);
+
+      if (creditUpdateError) throw new Error(creditUpdateError.message);
+    }
+
+    // Insert into the settlements table
+    const settlementData: SettlementInsert = {
+      id: creditInsertData.id,
+      credit_id: creditInsertData.id,
+      user_id: userId,
+      location_id: creditInsertData.location_id, // Should be updated by trigger
+    };
+
+    const { data: settlementInsertData, error: settlementError } = await this.supabase
+      .from("settlements")
+      .insert(settlementData)
+      .select()
+      .maybeSingle();
+
+    if (settlementError) throw new Error(settlementError.message);
+    if (!settlementInsertData) throw new Error("Settlement not inserted");
+  }
+}
diff --git a/src/adapters/supabase/helpers/tables/super.ts b/src/adapters/supabase/helpers/tables/super.ts
new file mode 100644
index 000000000..3f940f5e9
--- /dev/null
+++ b/src/adapters/supabase/helpers/tables/super.ts
@@ -0,0 +1,12 @@
+import { SupabaseClient } from "@supabase/supabase-js";
+import Runtime from "../../../../bindings/bot-runtime";
+
+export class Super {
+  protected supabase: SupabaseClient;
+  protected runtime: Runtime; // convenience accessor
+
+  constructor(supabase: SupabaseClient) {
+    this.supabase = supabase;
+    this.runtime = Runtime.getState();
+  }
+}
diff --git a/src/adapters/supabase/helpers/tables/user.ts b/src/adapters/supabase/helpers/tables/user.ts
new file mode 100644
index 000000000..1970de625
--- /dev/null
+++ b/src/adapters/supabase/helpers/tables/user.ts
@@ -0,0 +1,44 @@
+import { SupabaseClient } from "@supabase/supabase-js";
+import { Context as ProbotContext } from "probot";
+import { Database } from "../../types/database";
+import { Super } from "./super";
+
+export type UserRow = Database["public"]["Tables"]["users"]["Row"];
+export class User extends Super {
+  constructor(supabase: SupabaseClient) {
+    super(supabase);
+  }
+
+  public async getUserId(context: ProbotContext, username: string): Promise {
+    const { data } = await context.octokit.rest.users.getByUsername({ username });
+    return data.id;
+  }
+
+  public async getMultiplier(userId: number, repositoryId: number) {
+    const locationData = await this.runtime.adapters.supabase.locations.getLocationsFromRepo(repositoryId);
+    if (locationData && locationData.length > 0) {
+      const accessData = await this._getAccessData(locationData, userId);
+      if (accessData) {
+        return {
+          value: accessData.multiplier || null,
+          reason: accessData.multiplier_reason || null,
+        };
+      }
+    }
+    return null;
+  }
+
+  private async _getAccessData(locationData: { id: number }[], userId: number) {
+    const locationIdsInCurrentRepository = locationData.map((location) => location.id);
+
+    const { data: accessData, error: accessError } = await this.supabase
+      .from("access")
+      .select("multiplier, multiplier_reason")
+      .in("location_id", locationIdsInCurrentRepository)
+      .eq("user_id", userId)
+      .order("id", { ascending: false }) // get the latest one
+      .maybeSingle();
+    if (accessError) throw this.runtime.logger.fatal("Error getting access data", accessError);
+    return accessData;
+  }
+}
diff --git a/src/adapters/supabase/helpers/tables/wallet.test.ts b/src/adapters/supabase/helpers/tables/wallet.test.ts
new file mode 100644
index 000000000..8404b4c4b
--- /dev/null
+++ b/src/adapters/supabase/helpers/tables/wallet.test.ts
@@ -0,0 +1,26 @@
+import dotenv from "dotenv";
+dotenv.config();
+
+import { GitHubUser } from "../../../../types/payload";
+import { createAdapters } from "../../../adapters";
+const SUPABASE_URL = process.env.SUPABASE_URL;
+if (!SUPABASE_URL) throw new Error("SUPABASE_URL is not defined");
+const SUPABASE_KEY = process.env.SUPABASE_KEY;
+if (!SUPABASE_KEY) throw new Error("SUPABASE_KEY is not defined");
+
+async function getWalletAddressAndUrlTest() {
+  const { wallet } = createAdapters().supabase;
+  const userId = 4975670 as GitHubUser["id"];
+  const results = [] as unknown[];
+  try {
+    const address = await wallet.getAddress(userId);
+    // const url = await wallet.getWalletRegistrationUrl(userId);
+    results.push(address);
+    // results.push(url);
+  } catch (e) {
+    console.error(e);
+  }
+  console.trace(results);
+}
+
+void getWalletAddressAndUrlTest();
diff --git a/src/adapters/supabase/helpers/tables/wallet.ts b/src/adapters/supabase/helpers/tables/wallet.ts
new file mode 100644
index 000000000..804eae518
--- /dev/null
+++ b/src/adapters/supabase/helpers/tables/wallet.ts
@@ -0,0 +1,209 @@
+import { PostgrestError, SupabaseClient } from "@supabase/supabase-js";
+import { Context as ProbotContext } from "probot";
+import Runtime from "../../../../bindings/bot-runtime";
+import { GitHubUser } from "../../../../types/payload";
+
+import { Database } from "../../types/database";
+import { Super } from "./super";
+import { UserRow } from "./user";
+
+type LocationRow = Database["public"]["Tables"]["locations"]["Row"];
+type WalletRow = Database["public"]["Tables"]["wallets"]["Row"];
+type WalletInsert = Database["public"]["Tables"]["wallets"]["Insert"];
+type UserWithWallet = (UserRow & { wallets: WalletRow | null })[];
+
+type IssueCommentPayload =
+  | ProbotContext<"issue_comment.created">["payload"]
+  | ProbotContext<"issue_comment.edited">["payload"];
+
+export class Wallet extends Super {
+  constructor(supabase: SupabaseClient) {
+    super(supabase);
+  }
+
+  public async getAddress(id: number): Promise {
+    const userWithWallet = await this._getUserWithWallet(id);
+    return this._validateAndGetWalletAddress(userWithWallet);
+  }
+
+  public async upsertWalletAddress(context: ProbotContext, address: string) {
+    const payload = context.payload as
+      | ProbotContext<"issue_comment.created">["payload"]
+      | ProbotContext<"issue_comment.edited">["payload"];
+
+    const userData = await this._getUserData(payload);
+    const locationMetaData = this._getLocationMetaData(payload);
+
+    if (!userData.wallet_id) {
+      await this._registerNewWallet({
+        address,
+        locationMetaData,
+        payload,
+      });
+    } else {
+      const registeredWalletData = await this._getRegisteredWalletData(userData);
+      await this._updateExistingWallet({
+        address,
+        locationMetaData,
+        payload,
+        walletData: registeredWalletData,
+      });
+    }
+  }
+
+  private async _getUserWithWallet(id: number): Promise {
+    const { data, error } = await this.supabase.from("users").select("*, wallets(*)").filter("id", "eq", id);
+    if (error) throw error;
+    return data;
+  }
+
+  private _validateAndGetWalletAddress(userWithWallet: UserWithWallet): string {
+    // const payload = Runtime.getState().latestEventContext.payload;
+
+    if (userWithWallet[0]?.wallets?.address === undefined) throw new Error("Wallet address is undefined");
+    if (userWithWallet[0]?.wallets?.address === null) throw new Error("Wallet address is null");
+    return userWithWallet[0]?.wallets?.address;
+  }
+
+  private async _checkIfUserExists(userId: number) {
+    const { data, error } = await this.supabase.from("users").select("*").eq("id", userId).maybeSingle();
+    if (error) throw error;
+    return data as UserRow;
+  }
+
+  private async _getUserData(payload: IssueCommentPayload): Promise {
+    const user = await this._checkIfUserExists(payload.sender.id);
+    let userData = user;
+    if (!userData) {
+      const user = payload.sender as GitHubUser;
+      userData = await this._registerNewUser(user, this._getLocationMetaData(payload));
+    }
+    return userData;
+  }
+
+  private async _registerNewUser(user: GitHubUser, locationMetaData: LocationMetaData): Promise {
+    // Insert the location metadata into the locations table
+    const { data: locationData, error: locationError } = (await this.supabase
+      .from("locations")
+      .insert(locationMetaData)
+      .select()
+      .single()) as { data: LocationRow; error: PostgrestError | null };
+
+    if (locationError) {
+      throw new Error(locationError.message);
+    }
+    // Get the ID of the inserted location
+    const locationId = locationData.id;
+
+    // Register the new user with the location ID
+    const { data: userData, error: userError } = await this.supabase
+      .from("users")
+      .insert([{ id: user.id, location_id: locationId /* other fields if necessary */ }])
+      .select()
+      .single();
+
+    if (userError) {
+      throw new Error(userError.message);
+    }
+
+    return userData as UserRow;
+  }
+
+  private async _checkIfWalletExists(
+    userData: UserRow
+  ): Promise<{ data: WalletRow | null; error: PostgrestError | null }> {
+    const { data, error } = await this.supabase.from("wallets").select("*").eq("id", userData.wallet_id).maybeSingle();
+
+    return { data: data as WalletRow, error };
+  }
+
+  private async _updateWalletId(walletId: number, userId: number) {
+    const { error } = await this.supabase.from("users").update({ wallet_id: walletId }).eq("id", userId);
+
+    if (error) {
+      throw error;
+    }
+  }
+
+  private async _getRegisteredWalletData(userData: UserRow): Promise {
+    const walletResponse = await this._checkIfWalletExists(userData);
+    const walletData = walletResponse.data as WalletRow;
+    const walletError = walletResponse.error;
+
+    if (walletError) throw walletError;
+    return walletData;
+  }
+
+  private _getLocationMetaData(payload: IssueCommentPayload): LocationMetaData {
+    return {
+      user_id: payload.sender.id,
+      comment_id: payload.comment.id,
+      issue_id: payload.issue.id,
+      repository_id: payload.repository.id,
+      organization_id: payload.organization?.id ?? payload.repository.owner.id,
+    } as LocationMetaData;
+  }
+
+  private async _registerNewWallet({ address, locationMetaData, payload }: RegisterNewWallet) {
+    const walletData = await this._insertNewWallet(address);
+    await this._updateWalletId(walletData.id, payload.sender.id);
+    if (walletData.location_id) {
+      await this._enrichLocationMetaData(walletData, locationMetaData);
+    }
+  }
+
+  private async _updateExistingWallet({ address, locationMetaData, walletData }: UpdateExistingWallet) {
+    await this._updateWalletAddress(walletData.id, address);
+    if (walletData.location_id) {
+      await this._enrichLocationMetaData(walletData, locationMetaData);
+    }
+  }
+
+  private async _insertNewWallet(address: string): Promise {
+    const newWallet: WalletInsert = {
+      address: address,
+    };
+
+    const { data: walletInsertData, error: walletInsertError } = await this.supabase
+      .from("wallets")
+      .insert(newWallet)
+      .select()
+      .single();
+
+    if (walletInsertError) throw walletInsertError;
+    return walletInsertData as WalletRow;
+  }
+
+  private async _updateWalletAddress(walletId: number, address: string) {
+    const basicLocationInfo = {
+      address: address,
+    } as WalletRow;
+
+    await this.supabase.from("wallets").update(basicLocationInfo).eq("id", walletId).maybeSingle();
+  }
+
+  private async _enrichLocationMetaData(walletData: WalletRow, locationMetaData: LocationMetaData) {
+    const runtime = Runtime.getState();
+    const logger = runtime.logger;
+    logger.ok("Enriching wallet location metadata", locationMetaData);
+    return await this.supabase.from("locations").update(locationMetaData).eq("id", walletData.location_id);
+  }
+}
+
+interface RegisterNewWallet {
+  address: string;
+  payload: IssueCommentPayload;
+  locationMetaData: LocationMetaData;
+}
+
+interface UpdateExistingWallet extends RegisterNewWallet {
+  walletData: WalletRow;
+}
+
+interface LocationMetaData {
+  user_id: number;
+  comment_id: number;
+  issue_id: number;
+  repository_id: number;
+  organization_id: number;
+}
diff --git a/src/adapters/supabase/index.ts b/src/adapters/supabase/index.ts
deleted file mode 100644
index d4e09d7b4..000000000
--- a/src/adapters/supabase/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from "./helpers";
diff --git a/src/adapters/supabase/types/database.ts b/src/adapters/supabase/types/database.ts
index d2a8ce03e..b017bab16 100644
--- a/src/adapters/supabase/types/database.ts
+++ b/src/adapters/supabase/types/database.ts
@@ -1,385 +1,510 @@
-export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[];
+type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[];
 
 export interface Database {
-  graphql_public: {
-    Tables: {
-      [_ in never]: never;
-    };
-    Views: {
-      [_ in never]: never;
-    };
-    Functions: {
-      graphql: {
-        Args: {
-          operationName?: string;
-          query?: string;
-          variables?: Json;
-          extensions?: Json;
-        };
-        Returns: Json;
-      };
-    };
-    Enums: {
-      [_ in never]: never;
-    };
-    CompositeTypes: {
-      [_ in never]: never;
-    };
-  };
   public: {
     Tables: {
       access: {
         Row: {
-          created_at: string | null;
-          multiplier_access: boolean | null;
-          price_access: boolean | null;
-          priority_access: boolean | null;
-          repository: string | null;
-          time_access: boolean | null;
-          updated_at: string | null;
-          user_name: string;
+          created: string;
+          id: number;
+          labels: Json | null;
+          location_id: number | null;
+          multiplier: number;
+          multiplier_reason: string | null;
+          updated: string | null;
+          user_id: number;
         };
         Insert: {
-          created_at?: string | null;
-          multiplier_access?: boolean | null;
-          price_access?: boolean | null;
-          priority_access?: boolean | null;
-          repository?: string | null;
-          time_access?: boolean | null;
-          updated_at?: string | null;
-          user_name: string;
+          created?: string;
+          id?: number;
+          labels?: Json | null;
+          location_id?: number | null;
+          multiplier?: number;
+          multiplier_reason?: string | null;
+          updated?: string | null;
+          user_id: number;
         };
         Update: {
-          created_at?: string | null;
-          multiplier_access?: boolean | null;
-          price_access?: boolean | null;
-          priority_access?: boolean | null;
-          repository?: string | null;
-          time_access?: boolean | null;
-          updated_at?: string | null;
-          user_name?: string;
+          created?: string;
+          id?: number;
+          labels?: Json | null;
+          location_id?: number | null;
+          multiplier?: number;
+          multiplier_reason?: string | null;
+          updated?: string | null;
+          user_id?: number;
         };
-        Relationships: [];
+        Relationships: [
+          {
+            foreignKeyName: "access_user_id_fkey";
+            columns: ["user_id"];
+            referencedRelation: "users";
+            referencedColumns: ["id"];
+          },
+          {
+            foreignKeyName: "fk_access_location";
+            columns: ["location_id"];
+            referencedRelation: "locations";
+            referencedColumns: ["id"];
+          }
+        ];
       };
-      issues: {
+      credits: {
         Row: {
-          assignees: string[] | null;
-          closed_at: string | null;
-          comments_url: string;
-          completed_at: string | null;
-          created_at: string | null;
-          events_url: string;
+          amount: number;
+          created: string;
           id: number;
-          issue_number: number;
-          issue_url: string;
-          labels: string[] | null;
-          price: string | null;
-          priority: string | null;
-          recipient: string | null;
-          started_at: string | null;
-          status: Database["public"]["Enums"]["issue_status"];
-          timeline: string | null;
-          txhash: string[] | null;
-          updated_at: string | null;
+          location_id: number | null;
+          permit_id: number | null;
+          updated: string | null;
         };
         Insert: {
-          assignees?: string[] | null;
-          closed_at?: string | null;
-          comments_url: string;
-          completed_at?: string | null;
-          created_at?: string | null;
-          events_url: string;
+          amount: number;
+          created?: string;
           id?: number;
-          issue_number: number;
-          issue_url: string;
-          labels?: string[] | null;
-          price?: string | null;
-          priority?: string | null;
-          recipient?: string | null;
-          started_at?: string | null;
-          status?: Database["public"]["Enums"]["issue_status"];
-          timeline?: string | null;
-          txhash?: string[] | null;
-          updated_at?: string | null;
+          location_id?: number | null;
+          permit_id?: number | null;
+          updated?: string | null;
         };
         Update: {
-          assignees?: string[] | null;
-          closed_at?: string | null;
-          comments_url?: string;
-          completed_at?: string | null;
-          created_at?: string | null;
-          events_url?: string;
+          amount?: number;
+          created?: string;
           id?: number;
-          issue_number?: number;
-          issue_url?: string;
-          labels?: string[] | null;
-          price?: string | null;
-          priority?: string | null;
-          recipient?: string | null;
-          started_at?: string | null;
-          status?: Database["public"]["Enums"]["issue_status"];
-          timeline?: string | null;
-          txhash?: string[] | null;
-          updated_at?: string | null;
+          location_id?: number | null;
+          permit_id?: number | null;
+          updated?: string | null;
         };
-        Relationships: [];
+        Relationships: [
+          {
+            foreignKeyName: "credits_location_id_fkey";
+            columns: ["location_id"];
+            referencedRelation: "locations";
+            referencedColumns: ["id"];
+          },
+          {
+            foreignKeyName: "credits_permit_id_fkey";
+            columns: ["permit_id"];
+            referencedRelation: "permits";
+            referencedColumns: ["id"];
+          }
+        ];
       };
-      users: {
+      debits: {
         Row: {
-          bio: string | null;
-          blog: string | null;
-          company: string | null;
-          contributions: string | null;
-          created_at: string | null;
-          email: string | null;
-          followers: number | null;
-          following: number | null;
-          percent_code_reviews: number | null;
-          percent_commits: number | null;
-          percent_issues: number | null;
-          percent_pull_requests: number | null;
-          public_repos: number | null;
-          twitter_username: string | null;
-          updated_at: string | null;
-          user_location: string | null;
-          user_login: string;
-          user_name: string;
-          user_type: string | null;
-          wallet_address: string | null;
+          amount: number;
+          created: string;
+          id: number;
+          location_id: number | null;
+          token_id: number | null;
+          updated: string | null;
         };
         Insert: {
-          bio?: string | null;
-          blog?: string | null;
-          company?: string | null;
-          contributions?: string | null;
-          created_at?: string | null;
-          email?: string | null;
-          followers?: number | null;
-          following?: number | null;
-          percent_code_reviews?: number | null;
-          percent_commits?: number | null;
-          percent_issues?: number | null;
-          percent_pull_requests?: number | null;
-          public_repos?: number | null;
-          twitter_username?: string | null;
-          updated_at?: string | null;
-          user_location?: string | null;
-          user_login: string;
-          user_name: string;
-          user_type?: string | null;
-          wallet_address?: string | null;
+          amount: number;
+          created?: string;
+          id?: number;
+          location_id?: number | null;
+          token_id?: number | null;
+          updated?: string | null;
         };
         Update: {
-          bio?: string | null;
-          blog?: string | null;
-          company?: string | null;
-          contributions?: string | null;
-          created_at?: string | null;
-          email?: string | null;
-          followers?: number | null;
-          following?: number | null;
-          percent_code_reviews?: number | null;
-          percent_commits?: number | null;
-          percent_issues?: number | null;
-          percent_pull_requests?: number | null;
-          public_repos?: number | null;
-          twitter_username?: string | null;
-          updated_at?: string | null;
-          user_location?: string | null;
-          user_login?: string;
-          user_name?: string;
-          user_type?: string | null;
-          wallet_address?: string | null;
+          amount?: number;
+          created?: string;
+          id?: number;
+          location_id?: number | null;
+          token_id?: number | null;
+          updated?: string | null;
         };
-        Relationships: [];
+        Relationships: [
+          {
+            foreignKeyName: "debits_token_id_fkey";
+            columns: ["token_id"];
+            referencedRelation: "tokens";
+            referencedColumns: ["id"];
+          },
+          {
+            foreignKeyName: "fk_debits_location";
+            columns: ["location_id"];
+            referencedRelation: "locations";
+            referencedColumns: ["id"];
+          }
+        ];
       };
-      wallets: {
+      labels: {
         Row: {
-          created_at: string | null;
-          multiplier: number | null;
-          reason: string | null;
-          updated_at: string | null;
-          user_name: string;
-          wallet_address: string | null;
+          authorized: boolean | null;
+          created: string;
+          id: number;
+          label_from: string | null;
+          label_to: string | null;
+          location_id: number | null;
+          updated: string | null;
         };
         Insert: {
-          created_at?: string | null;
-          multiplier?: number | null;
-          reason?: string | null;
-          updated_at?: string | null;
-          user_name: string;
-          wallet_address?: string | null;
+          authorized?: boolean | null;
+          created?: string;
+          id?: number;
+          label_from?: string | null;
+          label_to?: string | null;
+          location_id?: number | null;
+          updated?: string | null;
         };
         Update: {
-          created_at?: string | null;
-          multiplier?: number | null;
-          reason?: string | null;
-          updated_at?: string | null;
-          user_name?: string;
-          wallet_address?: string | null;
+          authorized?: boolean | null;
+          created?: string;
+          id?: number;
+          label_from?: string | null;
+          label_to?: string | null;
+          location_id?: number | null;
+          updated?: string | null;
         };
-        Relationships: [];
+        Relationships: [
+          {
+            foreignKeyName: "labels_location_id_fkey";
+            columns: ["location_id"];
+            referencedRelation: "locations";
+            referencedColumns: ["id"];
+          }
+        ];
       };
-      weekly: {
+      locations: {
         Row: {
-          created_at: string | null;
-          last_time: string | null;
+          comment_id: number | null;
+          created: string;
+          id: number;
+          issue_id: number | null;
+          node_id: string | null;
+          node_type: string | null;
+          node_url: string | null;
+          organization_id: number | null;
+          repository_id: number | null;
+          updated: string | null;
+          user_id: number | null;
         };
         Insert: {
-          created_at?: string | null;
-          last_time?: string | null;
+          comment_id?: number | null;
+          created?: string;
+          id?: number;
+          issue_id?: number | null;
+          node_id?: string | null;
+          node_type?: string | null;
+          node_url?: string | null;
+          organization_id?: number | null;
+          repository_id?: number | null;
+          updated?: string | null;
+          user_id?: number | null;
         };
         Update: {
-          created_at?: string | null;
-          last_time?: string | null;
+          comment_id?: number | null;
+          created?: string;
+          id?: number;
+          issue_id?: number | null;
+          node_id?: string | null;
+          node_type?: string | null;
+          node_url?: string | null;
+          organization_id?: number | null;
+          repository_id?: number | null;
+          updated?: string | null;
+          user_id?: number | null;
         };
         Relationships: [];
       };
-    };
-    Views: {
-      [_ in never]: never;
-    };
-    Functions: {
-      add_penalty: {
-        Args: {
-          username: string;
-          repository_name: string;
-          token_address: string;
-          penalty_amount: string;
-        };
-        Returns: string;
+      logs: {
+        Row: {
+          created: string;
+          id: number;
+          level: string | null;
+          location_id: number | null;
+          log: string;
+          metadata: Json | null;
+          updated: string | null;
+        };
+        Insert: {
+          created?: string;
+          id?: number;
+          level?: string | null;
+          location_id?: number | null;
+          log: string;
+          metadata?: Json | null;
+          updated?: string | null;
+        };
+        Update: {
+          created?: string;
+          id?: number;
+          level?: string | null;
+          location_id?: number | null;
+          log?: string;
+          metadata?: Json | null;
+          updated?: string | null;
+        };
+        Relationships: [
+          {
+            foreignKeyName: "fk_logs_location";
+            columns: ["location_id"];
+            referencedRelation: "locations";
+            referencedColumns: ["id"];
+          }
+        ];
       };
-      deduct_penalty: {
-        Args: {
-          username: string;
-          repository_name: string;
-          token_address: string;
-          penalty_amount: string;
-        };
-        Returns: string;
+      partners: {
+        Row: {
+          created: string;
+          id: number;
+          location_id: number | null;
+          updated: string | null;
+          wallet_id: number | null;
+        };
+        Insert: {
+          created?: string;
+          id?: number;
+          location_id?: number | null;
+          updated?: string | null;
+          wallet_id?: number | null;
+        };
+        Update: {
+          created?: string;
+          id?: number;
+          location_id?: number | null;
+          updated?: string | null;
+          wallet_id?: number | null;
+        };
+        Relationships: [
+          {
+            foreignKeyName: "fk_partners_location";
+            columns: ["location_id"];
+            referencedRelation: "locations";
+            referencedColumns: ["id"];
+          },
+          {
+            foreignKeyName: "partners_wallet_id_fkey";
+            columns: ["wallet_id"];
+            referencedRelation: "wallets";
+            referencedColumns: ["id"];
+          }
+        ];
       };
-    };
-    Enums: {
-      issue_status: "READY_TO_START" | "IN_PROGRESS" | "IN_REVIEW" | "DONE";
-    };
-    CompositeTypes: {
-      [_ in never]: never;
-    };
-  };
-  storage: {
-    Tables: {
-      buckets: {
+      permits: {
         Row: {
-          allowed_mime_types: string[] | null;
-          avif_autodetection: boolean | null;
-          created_at: string | null;
-          file_size_limit: number | null;
-          id: string;
-          name: string;
-          owner: string | null;
-          public: boolean | null;
-          updated_at: string | null;
+          amount: string;
+          beneficiary_id: number;
+          created: string;
+          deadline: string;
+          id: number;
+          location_id: number | null;
+          nonce: string;
+          partner_id: number | null;
+          signature: string;
+          token_id: number | null;
+          transaction: string | null;
+          updated: string | null;
         };
         Insert: {
-          allowed_mime_types?: string[] | null;
-          avif_autodetection?: boolean | null;
-          created_at?: string | null;
-          file_size_limit?: number | null;
-          id: string;
-          name: string;
-          owner?: string | null;
-          public?: boolean | null;
-          updated_at?: string | null;
+          amount: string;
+          beneficiary_id: number;
+          created?: string;
+          deadline: string;
+          id?: number;
+          location_id?: number | null;
+          nonce: string;
+          partner_id?: number | null;
+          signature: string;
+          token_id?: number | null;
+          transaction?: string | null;
+          updated?: string | null;
         };
         Update: {
-          allowed_mime_types?: string[] | null;
-          avif_autodetection?: boolean | null;
-          created_at?: string | null;
-          file_size_limit?: number | null;
-          id?: string;
-          name?: string;
-          owner?: string | null;
-          public?: boolean | null;
-          updated_at?: string | null;
+          amount?: string;
+          beneficiary_id?: number;
+          created?: string;
+          deadline?: string;
+          id?: number;
+          location_id?: number | null;
+          nonce?: string;
+          partner_id?: number | null;
+          signature?: string;
+          token_id?: number | null;
+          transaction?: string | null;
+          updated?: string | null;
         };
         Relationships: [
           {
-            foreignKeyName: "buckets_owner_fkey";
-            columns: ["owner"];
+            foreignKeyName: "fk_permits_location";
+            columns: ["location_id"];
+            referencedRelation: "locations";
+            referencedColumns: ["id"];
+          },
+          {
+            foreignKeyName: "permits_beneficiary_id_fkey";
+            columns: ["beneficiary_id"];
             referencedRelation: "users";
             referencedColumns: ["id"];
+          },
+          {
+            foreignKeyName: "permits_partner_id_fkey";
+            columns: ["partner_id"];
+            referencedRelation: "partners";
+            referencedColumns: ["id"];
+          },
+          {
+            foreignKeyName: "permits_token_fkey";
+            columns: ["token_id"];
+            referencedRelation: "tokens";
+            referencedColumns: ["id"];
           }
         ];
       };
-      migrations: {
+      settlements: {
         Row: {
-          executed_at: string | null;
-          hash: string;
+          created: string;
+          credit_id: number | null;
+          debit_id: number | null;
           id: number;
-          name: string;
+          location_id: number | null;
+          updated: string | null;
+          user_id: number;
         };
         Insert: {
-          executed_at?: string | null;
-          hash: string;
+          created?: string;
+          credit_id?: number | null;
+          debit_id?: number | null;
+          id?: number;
+          location_id?: number | null;
+          updated?: string | null;
+          user_id: number;
+        };
+        Update: {
+          created?: string;
+          credit_id?: number | null;
+          debit_id?: number | null;
+          id?: number;
+          location_id?: number | null;
+          updated?: string | null;
+          user_id?: number;
+        };
+        Relationships: [
+          {
+            foreignKeyName: "fk_settlements_location";
+            columns: ["location_id"];
+            referencedRelation: "locations";
+            referencedColumns: ["id"];
+          },
+          {
+            foreignKeyName: "settlements_credit_id_fkey";
+            columns: ["credit_id"];
+            referencedRelation: "credits";
+            referencedColumns: ["id"];
+          },
+          {
+            foreignKeyName: "settlements_debit_id_fkey";
+            columns: ["debit_id"];
+            referencedRelation: "debits";
+            referencedColumns: ["id"];
+          },
+          {
+            foreignKeyName: "settlements_user_id_fkey";
+            columns: ["user_id"];
+            referencedRelation: "users";
+            referencedColumns: ["id"];
+          }
+        ];
+      };
+      tokens: {
+        Row: {
+          address: string;
+          created: string;
           id: number;
-          name: string;
+          location_id: number | null;
+          network: number;
+          updated: string | null;
+        };
+        Insert: {
+          address: string;
+          created?: string;
+          id?: number;
+          location_id?: number | null;
+          network?: number;
+          updated?: string | null;
         };
         Update: {
-          executed_at?: string | null;
-          hash?: string;
+          address?: string;
+          created?: string;
           id?: number;
-          name?: string;
+          location_id?: number | null;
+          network?: number;
+          updated?: string | null;
         };
-        Relationships: [];
+        Relationships: [
+          {
+            foreignKeyName: "tokens_location_id_fkey";
+            columns: ["location_id"];
+            referencedRelation: "locations";
+            referencedColumns: ["id"];
+          }
+        ];
       };
-      objects: {
+      users: {
         Row: {
-          bucket_id: string | null;
-          created_at: string | null;
-          id: string;
-          last_accessed_at: string | null;
-          metadata: Json | null;
-          name: string | null;
-          owner: string | null;
-          path_tokens: string[] | null;
-          updated_at: string | null;
-          version: string | null;
+          created: string;
+          id: number;
+          location_id: number | null;
+          updated: string | null;
+          wallet_id: number | null;
         };
         Insert: {
-          bucket_id?: string | null;
-          created_at?: string | null;
-          id?: string;
-          last_accessed_at?: string | null;
-          metadata?: Json | null;
-          name?: string | null;
-          owner?: string | null;
-          path_tokens?: string[] | null;
-          updated_at?: string | null;
-          version?: string | null;
+          created?: string;
+          id?: number;
+          location_id?: number | null;
+          updated?: string | null;
+          wallet_id?: number | null;
         };
         Update: {
-          bucket_id?: string | null;
-          created_at?: string | null;
-          id?: string;
-          last_accessed_at?: string | null;
-          metadata?: Json | null;
-          name?: string | null;
-          owner?: string | null;
-          path_tokens?: string[] | null;
-          updated_at?: string | null;
-          version?: string | null;
+          created?: string;
+          id?: number;
+          location_id?: number | null;
+          updated?: string | null;
+          wallet_id?: number | null;
         };
         Relationships: [
           {
-            foreignKeyName: "objects_bucketId_fkey";
-            columns: ["bucket_id"];
-            referencedRelation: "buckets";
+            foreignKeyName: "users_location_id_fkey";
+            columns: ["location_id"];
+            referencedRelation: "locations";
             referencedColumns: ["id"];
           },
           {
-            foreignKeyName: "objects_owner_fkey";
-            columns: ["owner"];
-            referencedRelation: "users";
+            foreignKeyName: "users_wallet_id_fkey";
+            columns: ["wallet_id"];
+            referencedRelation: "wallets";
+            referencedColumns: ["id"];
+          }
+        ];
+      };
+      wallets: {
+        Row: {
+          address: string | null;
+          created: string;
+          id: number;
+          location_id: number | null;
+          updated: string | null;
+        };
+        Insert: {
+          address?: string | null;
+          created?: string;
+          id?: number;
+          location_id?: number | null;
+          updated?: string | null;
+        };
+        Update: {
+          address?: string | null;
+          created?: string;
+          id?: number;
+          location_id?: number | null;
+          updated?: string | null;
+        };
+        Relationships: [
+          {
+            foreignKeyName: "wallets_location_id_fkey";
+            columns: ["location_id"];
+            referencedRelation: "locations";
             referencedColumns: ["id"];
           }
         ];
@@ -389,63 +514,73 @@ export interface Database {
       [_ in never]: never;
     };
     Functions: {
-      can_insert_object: {
-        Args: {
-          bucketid: string;
-          name: string;
-          owner: string;
-          metadata: Json;
-        };
-        Returns: undefined;
-      };
-      extension: {
-        Args: {
-          name: string;
-        };
-        Returns: string;
-      };
-      filename: {
-        Args: {
-          name: string;
-        };
-        Returns: string;
-      };
-      foldername: {
-        Args: {
-          name: string;
-        };
-        Returns: unknown;
-      };
-      get_size_by_bucket: {
-        Args: Record;
-        Returns: {
-          size: number;
-          bucket_id: string;
-        }[];
-      };
-      search: {
-        Args: {
-          prefix: string;
-          bucketname: string;
-          limits?: number;
-          levels?: number;
-          offsets?: number;
-          search?: string;
-          sortcolumn?: string;
-          sortorder?: string;
-        };
-        Returns: {
-          name: string;
-          id: string;
-          updated_at: string;
-          created_at: string;
-          last_accessed_at: string;
-          metadata: Json;
-        }[];
-      };
+      [_ in never]: never;
     };
     Enums: {
-      [_ in never]: never;
+      github_node_type:
+        | "App"
+        | "Bot"
+        | "CheckRun"
+        | "CheckSuite"
+        | "ClosedEvent"
+        | "CodeOfConduct"
+        | "Commit"
+        | "CommitComment"
+        | "CommitContributionsByRepository"
+        | "ContributingGuidelines"
+        | "ConvertToDraftEvent"
+        | "CreatedCommitContribution"
+        | "CreatedIssueContribution"
+        | "CreatedPullRequestContribution"
+        | "CreatedPullRequestReviewContribution"
+        | "CreatedRepositoryContribution"
+        | "CrossReferencedEvent"
+        | "Discussion"
+        | "DiscussionComment"
+        | "Enterprise"
+        | "EnterpriseUserAccount"
+        | "FundingLink"
+        | "Gist"
+        | "Issue"
+        | "IssueComment"
+        | "JoinedGitHubContribution"
+        | "Label"
+        | "License"
+        | "Mannequin"
+        | "MarketplaceCategory"
+        | "MarketplaceListing"
+        | "MergeQueue"
+        | "MergedEvent"
+        | "MigrationSource"
+        | "Milestone"
+        | "Organization"
+        | "PackageFile"
+        | "Project"
+        | "ProjectCard"
+        | "ProjectColumn"
+        | "ProjectV2"
+        | "PullRequest"
+        | "PullRequestCommit"
+        | "PullRequestReview"
+        | "PullRequestReviewComment"
+        | "ReadyForReviewEvent"
+        | "Release"
+        | "ReleaseAsset"
+        | "Repository"
+        | "RepositoryContactLink"
+        | "RepositoryTopic"
+        | "RestrictedContribution"
+        | "ReviewDismissedEvent"
+        | "SecurityAdvisoryReference"
+        | "SocialAccount"
+        | "SponsorsListing"
+        | "Team"
+        | "TeamDiscussion"
+        | "TeamDiscussionComment"
+        | "User"
+        | "Workflow"
+        | "WorkflowRun"
+        | "WorkflowRunFile";
     };
     CompositeTypes: {
       [_ in never]: never;
diff --git a/src/adapters/supabase/types/index.ts b/src/adapters/supabase/types/index.ts
deleted file mode 100644
index c30cd664d..000000000
--- a/src/adapters/supabase/types/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from "./database";
diff --git a/src/adapters/telegram/helpers/client.ts b/src/adapters/telegram/helpers/client.ts
deleted file mode 100644
index 4a54afc09..000000000
--- a/src/adapters/telegram/helpers/client.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import { Input } from "telegraf";
-import { getAdapters, getBotConfig } from "../../../bindings";
-import { TLMessageFormattedPayload, TLMessagePayload, TLPhotoPayload } from "../types/payload";
-
-export function messageFormatter(messagePayload: TLMessagePayload) {
-  const { action, title, description, id, ref, user } = messagePayload;
-  const msgObj =
-    `${action}: ${title} ` +
-    `#${id} ` +
-    `@` +
-    `${user}\n` +
-    `${description}`;
-
-  return msgObj;
-}
-
-export async function telegramFormattedNotifier(messagePayload: TLMessageFormattedPayload) {
-  const {
-    telegram: { delay },
-  } = getBotConfig();
-  const { telegram } = getAdapters();
-  const { chatIds, text, parseMode } = messagePayload;
-
-  let currentElem = 0;
-
-  const sendHandler = () => {
-    if (currentElem === chatIds.length) {
-      return;
-    }
-
-    const sendInterval = setInterval(async () => {
-      clearInterval(sendInterval);
-      await telegram.sendMessage(chatIds[currentElem], text, {
-        parse_mode: parseMode,
-      });
-      currentElem++;
-      sendHandler();
-    }, delay);
-  };
-  sendHandler();
-}
-
-export async function telegramNotifier(messagePayload: TLMessagePayload) {
-  const messageString = messageFormatter(messagePayload);
-  const messageObj: TLMessageFormattedPayload = {
-    chatIds: messagePayload.chatIds,
-    text: messageString,
-    parseMode: "HTML",
-  };
-  await telegramFormattedNotifier(messageObj);
-}
-
-export async function telegramPhotoNotifier(messagePayload: TLPhotoPayload) {
-  const { chatId, file, caption } = messagePayload;
-  const { telegram } = getAdapters();
-  await telegram.sendPhoto(chatId, Input.fromLocalFile(file), { caption: caption, parse_mode: "HTML" });
-}
diff --git a/src/adapters/telegram/helpers/index.ts b/src/adapters/telegram/helpers/index.ts
deleted file mode 100644
index 5ec76921e..000000000
--- a/src/adapters/telegram/helpers/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from "./client";
diff --git a/src/adapters/telegram/index.ts b/src/adapters/telegram/index.ts
deleted file mode 100644
index 872ef39cc..000000000
--- a/src/adapters/telegram/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from "./helpers";
-export * from "./types";
diff --git a/src/adapters/telegram/types/index.ts b/src/adapters/telegram/types/index.ts
deleted file mode 100644
index 87037153a..000000000
--- a/src/adapters/telegram/types/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from "./payload";
diff --git a/src/adapters/telegram/types/payload.ts b/src/adapters/telegram/types/payload.ts
deleted file mode 100644
index b19f8f132..000000000
--- a/src/adapters/telegram/types/payload.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { ParseMode } from "telegraf/types";
-
-/**
- * @type {Object} MessagePayload
- * @property {chatIds} - chatId array ([10001,10002])
- * @property {action} - action name (`new issue` | `new pull request`)
- * @property {title} - message title (`feat: support for x`)
- * @property {description} - message description (`build: change x for y`)
- * @property {id} - issue | pull id (`54`)
- * @property {ref} - base url (`https://github.com/x/issues|pull/54`)
- * @property {user} - username (`x-user`)
- */
-export type TLMessagePayload = {
-  chatIds: string[];
-  action: string;
-  title: string;
-  description: string;
-  id: string;
-  ref: string;
-  user: string;
-};
-
-/**
- * @type {Object} FormattedMessagePayload
- * @property {chatIds} - chatId array ([10001,10002])
- * @property {text} - formatted text (`new issue: support for x`)
- * @property {parseMode} - parseMode (`HTML|Markdown|MarkdownV2`)
- */
-export type TLMessageFormattedPayload = {
-  chatIds: string[];
-  text: string;
-  parseMode: ParseMode;
-};
-
-/**
- * @type {Object} PhotoPayload
- * @property {chatId} - chatId  (`10001`)
- * @property {file} - relative file path (`./assets/file.png`)
- * @property {caption} - text caption (`opened issues: 10`)
- */
-export type TLPhotoPayload = {
-  chatId: string;
-  file: string;
-  caption: string;
-};
diff --git a/src/assets/fonts/proxima-nova-regular-b64.ts b/src/assets/fonts/proxima-nova-regular-b64.ts
deleted file mode 100644
index e558fa5e0..000000000
--- a/src/assets/fonts/proxima-nova-regular-b64.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// cspell:disable
-export const ProximaNovaRegularBase64 = `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`;
diff --git a/src/assets/images/flat.png b/src/assets/images/flat.png
deleted file mode 100644
index e4788c92c..000000000
Binary files a/src/assets/images/flat.png and /dev/null differ
diff --git a/src/assets/svgs/closed-issue.ts b/src/assets/svgs/closed-issue.ts
deleted file mode 100644
index a49bbd57a..000000000
--- a/src/assets/svgs/closed-issue.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-export const ClosedIssueIcon = `
-    
-        
-        
-    
-    
-        
-            
-        
-    
-`;
diff --git a/src/assets/svgs/commit.ts b/src/assets/svgs/commit.ts
deleted file mode 100644
index 900e00629..000000000
--- a/src/assets/svgs/commit.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export const CommitIcon = `
-    
-`;
diff --git a/src/assets/svgs/index.ts b/src/assets/svgs/index.ts
deleted file mode 100644
index 35c318d80..000000000
--- a/src/assets/svgs/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export * from "./commit";
-export * from "./opened-issue";
-export * from "./closed-issue";
-export * from "./opened-pull";
-export * from "./merged-pull";
diff --git a/src/assets/svgs/merged-pull.ts b/src/assets/svgs/merged-pull.ts
deleted file mode 100644
index e014acd34..000000000
--- a/src/assets/svgs/merged-pull.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export const MergedPullIcon = `
-    
-`;
diff --git a/src/assets/svgs/opened-issue.ts b/src/assets/svgs/opened-issue.ts
deleted file mode 100644
index 235b9d6b7..000000000
--- a/src/assets/svgs/opened-issue.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-export const OpenedIssueIcon = `
-    
-        
-        
-    
-    
-        
-            
-        
-    
-`;
diff --git a/src/assets/svgs/opened-pull.ts b/src/assets/svgs/opened-pull.ts
deleted file mode 100644
index be745fa0f..000000000
--- a/src/assets/svgs/opened-pull.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export const OpenedPullIcon = `
-    
-`;
diff --git a/src/bindings/bot-runtime.ts b/src/bindings/bot-runtime.ts
new file mode 100644
index 000000000..8fadaba14
--- /dev/null
+++ b/src/bindings/bot-runtime.ts
@@ -0,0 +1,38 @@
+import { createAdapters } from "../adapters/adapters";
+import { Logs } from "ubiquibot-logger";
+
+class Runtime {
+  private static _instance: Runtime;
+  private _adapters: ReturnType;
+  private _logger: Logs;
+
+  private constructor() {
+    this._adapters = {} as ReturnType;
+    this._logger = {} as Logs;
+  }
+
+  public static getState(): Runtime {
+    if (!Runtime._instance) {
+      Runtime._instance = new Runtime();
+    }
+    return Runtime._instance;
+  }
+
+  public get adapters(): ReturnType {
+    return this._adapters;
+  }
+
+  public set adapters(adapters: ReturnType) {
+    this._adapters = adapters;
+  }
+
+  public get logger(): Logs {
+    return this._logger;
+  }
+
+  public set logger(logger: Logs) {
+    this._logger = logger;
+  }
+}
+
+export default Runtime;
diff --git a/src/bindings/config.ts b/src/bindings/config.ts
deleted file mode 100644
index 55d0fb8be..000000000
--- a/src/bindings/config.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-import ms from "ms";
-
-import { BotConfig, BotConfigSchema, LogLevel } from "../types";
-import { getPayoutConfigByNetworkId } from "../helpers";
-import { ajv } from "../utils";
-import { Context } from "probot";
-import { getScalarKey, getWideConfig } from "../utils/private";
-
-export const loadConfig = async (context: Context): Promise => {
-  const {
-    baseMultiplier,
-    timeLabels,
-    privateKey,
-    priorityLabels,
-    incentives,
-    paymentPermitMaxPrice,
-    disableAnalytics,
-    bountyHunterMax,
-    incentiveMode,
-    networkId,
-    issueCreatorMultiplier,
-    defaultLabels,
-    promotionComment,
-    commandSettings,
-    assistivePricing,
-    registerWalletWithVerification,
-    staleBountyTime,
-    enableAccessControl,
-    openAIKey,
-    openAITokenLimit,
-    newContributorGreeting,
-    timeRangeForMaxIssueEnabled,
-    timeRangeForMaxIssue,
-    permitBaseUrl,
-    botDelay,
-    followUpTime,
-    disqualifyTime,
-  } = await getWideConfig(context);
-
-  const publicKey = await getScalarKey(process.env.X25519_PRIVATE_KEY);
-  const { rpc, paymentToken } = getPayoutConfigByNetworkId(networkId);
-
-  const botConfig: BotConfig = {
-    log: {
-      logEnvironment: process.env.LOG_ENVIRONMENT || "production",
-      level: (process.env.LOG_LEVEL as LogLevel) || LogLevel.DEBUG,
-      retryLimit: Number(process.env.LOG_RETRY) || 0,
-    },
-    price: {
-      baseMultiplier,
-      issueCreatorMultiplier,
-      timeLabels,
-      priorityLabels,
-      incentives,
-      defaultLabels,
-    },
-    comments: {
-      promotionComment: promotionComment,
-    },
-    payout: {
-      networkId: networkId,
-      rpc: rpc,
-      privateKey: privateKey,
-      paymentToken: paymentToken,
-      permitBaseUrl: process.env.PERMIT_BASE_URL || permitBaseUrl,
-    },
-    unassign: {
-      timeRangeForMaxIssue: process.env.DEFAULT_TIME_RANGE_FOR_MAX_ISSUE
-        ? Number(process.env.DEFAULT_TIME_RANGE_FOR_MAX_ISSUE)
-        : timeRangeForMaxIssue,
-      timeRangeForMaxIssueEnabled: process.env.DEFAULT_TIME_RANGE_FOR_MAX_ISSUE_ENABLED
-        ? process.env.DEFAULT_TIME_RANGE_FOR_MAX_ISSUE_ENABLED == "true"
-        : timeRangeForMaxIssueEnabled,
-      followUpTime: ms(process.env.FOLLOW_UP_TIME || followUpTime),
-      disqualifyTime: ms(process.env.DISQUALIFY_TIME || disqualifyTime),
-    },
-    supabase: {
-      url: process.env.SUPABASE_URL ?? "",
-      key: process.env.SUPABASE_KEY ?? "",
-    },
-    telegram: {
-      token: process.env.TELEGRAM_BOT_TOKEN ?? "",
-      delay: process.env.TELEGRAM_BOT_DELAY ? Number(process.env.TELEGRAM_BOT_DELAY) : botDelay,
-    },
-    logNotification: {
-      url: process.env.LOG_WEBHOOK_BOT_URL || "",
-      secret: process.env.LOG_WEBHOOK_SECRET || "",
-      groupId: Number(process.env.LOG_WEBHOOK_GROUP_ID) || 0,
-      topicId: Number(process.env.LOG_WEBHOOK_TOPIC_ID) || 0,
-      enabled: true,
-    },
-    mode: {
-      paymentPermitMaxPrice: paymentPermitMaxPrice,
-      disableAnalytics: disableAnalytics,
-      incentiveMode: incentiveMode,
-      assistivePricing: assistivePricing,
-    },
-    command: commandSettings,
-    assign: {
-      bountyHunterMax: bountyHunterMax,
-      staleBountyTime: ms(staleBountyTime),
-    },
-    sodium: {
-      privateKey: process.env.X25519_PRIVATE_KEY ?? "",
-      publicKey: publicKey ?? "",
-    },
-    wallet: {
-      registerWalletWithVerification: registerWalletWithVerification,
-    },
-    ask: {
-      apiKey: openAIKey,
-      tokenLimit: openAITokenLimit || 0,
-    },
-    accessControl: enableAccessControl,
-    newContributorGreeting: newContributorGreeting,
-  };
-
-  if (botConfig.payout.privateKey == "") {
-    botConfig.mode.paymentPermitMaxPrice = 0;
-  }
-
-  if (botConfig.logNotification.secret == "" || botConfig.logNotification.groupId == 0 || botConfig.logNotification.url == "") {
-    botConfig.logNotification.enabled = false;
-  }
-
-  const validate = ajv.compile(BotConfigSchema);
-  const valid = validate(botConfig);
-  if (!valid) {
-    throw new Error(validate.errors?.map((err: unknown) => JSON.stringify(err, null, 2)).join(","));
-  }
-
-  if (botConfig.unassign.followUpTime < 0 || botConfig.unassign.disqualifyTime < 0) {
-    throw new Error(`Invalid time interval, followUpTime: ${botConfig.unassign.followUpTime}, disqualifyTime: ${botConfig.unassign.disqualifyTime}`);
-  }
-
-  return botConfig;
-};
diff --git a/src/bindings/env.ts b/src/bindings/env.ts
new file mode 100644
index 000000000..d2f300a08
--- /dev/null
+++ b/src/bindings/env.ts
@@ -0,0 +1,10 @@
+import { EnvConfig, validateEnvConfig } from "../types/configuration-types";
+import dotenv from "dotenv";
+dotenv.config();
+
+export const env = { ...process.env } as unknown as EnvConfig;
+
+const isValid = validateEnvConfig(env);
+if (!isValid) {
+  throw new Error("Invalid env configuration: " + JSON.stringify(validateEnvConfig.errors, null, 2));
+}
diff --git a/src/bindings/event.ts b/src/bindings/event.ts
index e3895541a..ce8d10303 100644
--- a/src/bindings/event.ts
+++ b/src/bindings/event.ts
@@ -1,146 +1,263 @@
-import { Context } from "probot";
-import { createAdapters } from "../adapters";
+import OpenAI from "openai";
+import { Context as ProbotContext } from "probot";
+import { LogReturn, Logs } from "ubiquibot-logger";
+import zlib from "zlib";
+import { createAdapters, supabaseClient } from "../adapters/adapters";
 import { processors, wildcardProcessors } from "../handlers/processors";
-import { shouldSkip } from "../helpers";
-import { BotConfig, GithubEvent, Payload, PayloadSchema, LogLevel } from "../types";
-import { Adapters } from "../types/adapters";
-import { ajv } from "../utils";
-import { loadConfig } from "./config";
-import { GitHubLogger } from "../adapters/supabase";
-import { validateConfigChange } from "../handlers/push";
-
-let botContext: Context = {} as Context;
-export const getBotContext = () => botContext;
-
-let botConfig: BotConfig = {} as BotConfig;
-export const getBotConfig = () => botConfig;
-
-let adapters: Adapters = {} as Adapters;
-export const getAdapters = () => adapters;
-
-export type Logger = {
-  info: (msg: string | object, options?: JSON) => void;
-  debug: (msg: string | object, options?: JSON) => void;
-  warn: (msg: string | object, options?: JSON) => void;
-  error: (msg: string | object, options?: JSON) => void;
-};
-
-let logger: Logger;
-export const getLogger = (): Logger => logger;
-
-const NO_VALIDATION = [GithubEvent.INSTALLATION_ADDED_EVENT as string, GithubEvent.PUSH_EVENT as string];
-
-export const bindEvents = async (context: Context): Promise => {
-  const { id, name } = context;
-  botContext = context;
-  const payload = context.payload as Payload;
-  const allowedEvents = Object.values(GithubEvent) as string[];
-  const eventName = payload.action ? `${name}.${payload.action}` : name; // some events wont have actions as this grows
-
-  let botConfigError;
-  try {
-    botConfig = await loadConfig(context);
-  } catch (err) {
-    botConfigError = err;
-  }
+import { validateConfigChange } from "../handlers/push/push";
+import structuredMetadata from "../handlers/shared/structured-metadata";
+import { BotConfig } from "../types/configuration-types";
 
-  adapters = createAdapters(botConfig);
+import { addCommentToIssue } from "../helpers/issue";
+import { shouldSkip } from "../helpers/shared";
+import { Context } from "../types/context";
+import {
+  HandlerReturnValuesNoVoid,
+  MainActionHandler,
+  PostActionHandler,
+  PreActionHandler,
+  WildCardHandler,
+} from "../types/handlers";
+import { GitHubEvent, GitHubPayload, payloadSchema } from "../types/payload";
+import { ajv } from "../utils/ajv";
+import { generateConfiguration } from "../utils/generate-configuration";
+import Runtime from "./bot-runtime";
+import { env } from "./env";
 
-  const options = {
-    app: "UbiquiBot",
-    // level: botConfig.log.level,
-  };
+const allowedEvents = Object.values(GitHubEvent) as string[];
 
-  logger = new GitHubLogger(
-    options.app,
-    botConfig?.log?.logEnvironment ?? "development",
-    botConfig?.log?.level ?? LogLevel.DEBUG,
-    botConfig?.log?.retryLimit ?? 0,
-    botConfig.logNotification
-  ); // contributors will see logs in console while on development env
-  if (!logger) {
-    return;
-  }
+const NO_VALIDATION = [GitHubEvent.INSTALLATION_ADDED_EVENT, GitHubEvent.PUSH_EVENT] as string[];
+type PreHandlerWithType = { type: string; actions: PreActionHandler[] };
+type HandlerWithType = { type: string; actions: MainActionHandler[] };
+type WildCardHandlerWithType = { type: string; actions: WildCardHandler[] };
+type PostHandlerWithType = { type: string; actions: PostActionHandler[] };
+type AllHandlersWithTypes = PreHandlerWithType | HandlerWithType | PostHandlerWithType;
+type AllHandlers = PreActionHandler | MainActionHandler | PostActionHandler;
 
-  if (botConfigError) {
-    logger.error(botConfigError.toString());
-    if (eventName === GithubEvent.PUSH_EVENT) {
-      await validateConfigChange();
-    }
-    return;
-  }
+const validatePayload = ajv.compile(payloadSchema);
 
-  // Create adapters for telegram, supabase, twitter, discord, etc
-  logger.info("Creating adapters for supabase, telegram, twitter, etc...");
+const runtime = Runtime.getState();
+runtime.adapters = createAdapters();
+runtime.logger = runtime.adapters.supabase.logs;
 
-  logger.info(
-    `Config loaded! config: ${JSON.stringify({
-      price: botConfig.price,
-      unassign: botConfig.unassign,
-      mode: botConfig.mode,
-      log: botConfig.log,
-      wallet: botConfig.wallet,
-    })}`
-  );
+export async function bindEvents(eventContext: ProbotContext) {
+  const payload = eventContext.payload as GitHubPayload;
+  const eventName = payload?.action ? `${eventContext.name}.${payload?.action}` : eventContext.name; // some events wont have actions as this grows
+  const logger = new Logs(supabaseClient, env.LOG_RETRY_LIMIT, env.LOG_LEVEL, eventContext);
 
-  logger.info(`Started binding events... id: ${id}, name: ${eventName}, allowedEvents: ${allowedEvents}`);
+  logger.info("Event received", { id: eventContext.id, name: eventName });
 
-  if (!allowedEvents.includes(eventName)) {
+  if (!allowedEvents.includes(eventName) && eventContext.name !== "repository_dispatch") {
     // just check if its on the watch list
-    logger.info(`Skipping the event. reason: not configured`);
-    return;
+    return logger.info(`Skipping the event. reason: not configured`);
   }
 
   // Skip validation for installation event and push
   if (!NO_VALIDATION.includes(eventName)) {
     // Validate payload
-    const validate = ajv.compile(PayloadSchema);
-    const valid = validate(payload);
-    if (!valid) {
-      logger.info("Payload schema validation failed!!!", payload);
-      if (validate.errors) logger.warn(validate.errors);
-      return;
+    const isValid = validatePayload(payload);
+    if (!isValid && validatePayload.errors) {
+      return logger.error("Payload schema validation failed!", validatePayload.errors);
     }
 
     // Check if we should skip the event
-    const { skip, reason } = shouldSkip();
-    if (skip) {
-      logger.info(`Skipping the event. reason: ${reason}`);
-      return;
+    const should = shouldSkip(eventContext);
+    if (should.stop) {
+      return logger.info("Skipping the event.", { reason: should.reason });
     }
   }
 
-  // Get the handlers for the action
-  const handlers = processors[eventName];
-  if (!handlers) {
-    logger.warn(`No handler configured for event: ${eventName}`);
+  if (eventName === GitHubEvent.PUSH_EVENT) {
+    await validateConfigChange(eventContext);
+  }
+
+  let botConfig: BotConfig;
+  try {
+    botConfig = await generateConfiguration(eventContext);
+  } catch (error) {
     return;
   }
+  const context: Context = {
+    event: eventContext,
+    config: botConfig,
+    openAi: botConfig.keys.openAi ? new OpenAI({ apiKey: botConfig.keys.openAi }) : null,
+    logger: logger,
+    payload: payload,
+    octokit: eventContext.octokit,
+  };
+
+  if (!context.config.keys.evmPrivateEncrypted) {
+    context.logger.error("No EVM private key found");
+  }
 
-  const { pre, action, post } = handlers;
-  // Run pre-handlers
-  logger.info(`Running pre handlers: ${pre.map((fn) => fn.name)}, event: ${eventName}`);
-  for (const preAction of pre) {
-    await preAction();
+  if (!context.logger) {
+    throw new Error("Failed to create logger");
   }
-  // Run main handlers
-  logger.info(`Running main handlers: ${action.map((fn) => fn.name)}, event: ${eventName}`);
-  for (const mainAction of action) {
-    await mainAction();
+
+  if (eventContext.name === GitHubEvent.REPOSITORY_DISPATCH) {
+    const dispatchPayload = payload as any;
+    if (payload.action === "issueClosed") {
+      //This is response for issueClosed request
+      const response = dispatchPayload.client_payload.result;
+      if (response) {
+        const uncompressedComment = zlib.gunzipSync(Buffer.from(response));
+        await addCommentToIssue(
+          context,
+          uncompressedComment.toString(),
+          parseInt(dispatchPayload.client_payload.issueNumber)
+        );
+      }
+    }
+  }
+
+  // Get the handlers for the action
+  const handlers = processors[eventName];
+
+  if (!handlers) {
+    return context.logger.error("No handler configured for event:", { eventName });
   }
+  const { pre, action, post } = handlers;
+
+  const handlerWithTypes: AllHandlersWithTypes[] = [
+    { type: "pre", actions: pre },
+    { type: "main", actions: action },
+    { type: "post", actions: post },
+  ];
 
-  // Run post-handlers
-  logger.info(`Running post handlers: ${post.map((fn) => fn.name)}, event: ${eventName}`);
-  for (const postAction of post) {
-    await postAction();
+  for (const handlerWithType of handlerWithTypes) {
+    // List all the function names of handlerType.actions
+    const functionNames = handlerWithType.actions.map((action) => action?.name);
+
+    context.logger.info(
+      `Running "${handlerWithType.type}" \
+      for event: "${eventName}". \
+      handlers: "${functionNames.join(", ")}"`
+    );
+
+    await logAnyReturnFromHandlers(context, handlerWithType);
   }
 
   // Skip wildcard handlers for installation event and push event
-  if (eventName !== GithubEvent.INSTALLATION_ADDED_EVENT && eventName !== GithubEvent.PUSH_EVENT) {
+  if (eventName == GitHubEvent.INSTALLATION_ADDED_EVENT || eventName == GitHubEvent.PUSH_EVENT) {
+    return context.logger.info("Skipping wildcard handlers for event:", eventName);
+  } else {
     // Run wildcard handlers
-    logger.info(`Running wildcard handlers: ${wildcardProcessors.map((fn) => fn.name)}`);
-    for (const wildcardProcessor of wildcardProcessors) {
-      await wildcardProcessor();
+    const functionNames = wildcardProcessors.map((action) => action?.name);
+    context.logger.info(`Running wildcard handlers: "${functionNames.join(", ")}"`);
+    const wildCardHandlerType: WildCardHandlerWithType = { type: "wildcard", actions: wildcardProcessors };
+    await logAnyReturnFromHandlers(context, wildCardHandlerType);
+  }
+}
+
+async function logAnyReturnFromHandlers(context: Context, handlerType: AllHandlersWithTypes) {
+  for (const action of handlerType.actions) {
+    const renderCatchAllWithContext = createRenderCatchAll(context, handlerType, action);
+    try {
+      // checkHandler(action);
+      const response = await action(context);
+
+      if (handlerType.type === "main") {
+        // only log main handler results
+        await renderMainActionOutput(context, response, action);
+      } else {
+        // context.logger.ok("Completed", { action: action.name, type: handlerType.type });
+      }
+    } catch (report: unknown) {
+      await renderCatchAllWithContext(report);
     }
   }
-};
+}
+
+async function renderMainActionOutput(
+  context: Context,
+  response: void | HandlerReturnValuesNoVoid,
+  action: AllHandlers
+) {
+  const { payload, logger } = context;
+  const issueNumber = payload.issue?.number;
+  if (!issueNumber) {
+    throw new Error("No issue number found");
+  }
+
+  if (response instanceof LogReturn) {
+    let serializedComment;
+    if (response.metadata) {
+      serializedComment = [
+        response.logMessage.diff,
+        structuredMetadata.create(response.logMessage.type, response.metadata),
+      ].join("\n");
+    } else {
+      serializedComment = response.logMessage.diff;
+    }
+
+    await addCommentToIssue(context, serializedComment, issueNumber);
+  } else if (typeof response == "string") {
+    await addCommentToIssue(context, response, issueNumber);
+  } else if (response === null) {
+    logger.debug("null response", { action: action.name });
+  } else {
+    logger.error(
+      "No response from action. Ensure return of string, null, or LogReturn object",
+      { action: action.name },
+      true
+    );
+  }
+}
+
+function createRenderCatchAll(context: Context, handlerType: AllHandlersWithTypes, activeHandler: AllHandlers) {
+  return async function renderCatchAll(report: LogReturn | Error | unknown) {
+    const payload = context.event.payload as GitHubPayload;
+    const issue = payload.issue;
+    if (!issue) {
+      return context.logger.error("Issue is null. Skipping", { issue });
+    }
+
+    if (report instanceof LogReturn) {
+      // already made it to console so it should just post the comment
+
+      if (report.metadata) {
+        return await addCommentToIssue(
+          context,
+          [report.logMessage.diff, structuredMetadata.create(report.logMessage.type, report.metadata)].join("\n"),
+          issue.number
+        );
+      } else {
+        return await addCommentToIssue(context, report.logMessage.diff, issue.number);
+      }
+    } else if (report instanceof Error) {
+      // convert error to normal object
+      // this is now handled inside of the logger
+      // TODO: test this
+
+      // const error = {
+      //   name: report.name,
+      //   message: report.message,
+      //   stack: report.stack,
+      // };
+
+      return context.logger.error(
+        "action has an uncaught error",
+        {
+          handlerType,
+          activeHandler: activeHandler.name,
+          error: report,
+        },
+        true
+      );
+    } else {
+      // could be supabase error
+
+      // report as SupabaseError
+
+      return context.logger.error(
+        "action returned an unexpected value",
+        {
+          logReturn: report,
+          handlerType,
+          activeHandler: activeHandler.name,
+        },
+        true
+      );
+    }
+  };
+}
diff --git a/src/bindings/index.ts b/src/bindings/index.ts
deleted file mode 100644
index 1258c85f4..000000000
--- a/src/bindings/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from "./event";
-export * from "./config";
diff --git a/src/commit-hash.ts b/src/commit-hash.ts
new file mode 100644
index 000000000..be71043ba
--- /dev/null
+++ b/src/commit-hash.ts
@@ -0,0 +1,8 @@
+import { execSync } from "child_process";
+export let COMMIT_HASH: null | string = null; // "0000000000000000000000000000000000000000";
+
+try {
+  COMMIT_HASH = execSync("git rev-parse --short HEAD").toString().trim();
+} catch (e) {
+  // netlify has no git binary
+}
diff --git a/src/configs/abis.ts b/src/configs/abis.ts
deleted file mode 100644
index 6f2c9ed85..000000000
--- a/src/configs/abis.ts
+++ /dev/null
@@ -1,159 +0,0 @@
-export const ERC20ABI = [
-  {
-    constant: true,
-    inputs: [],
-    name: "name",
-    outputs: [{ name: "", type: "string" }],
-    payable: false,
-    stateMutability: "view",
-    type: "function",
-  },
-  {
-    constant: false,
-    inputs: [
-      { name: "_spender", type: "address" },
-      { name: "_value", type: "uint256" },
-    ],
-    name: "approve",
-    outputs: [{ name: "success", type: "bool" }],
-    payable: false,
-    stateMutability: "nonpayable",
-    type: "function",
-  },
-  {
-    constant: true,
-    inputs: [],
-    name: "totalSupply",
-    outputs: [{ name: "", type: "uint256" }],
-    payable: false,
-    stateMutability: "view",
-    type: "function",
-  },
-  {
-    constant: false,
-    inputs: [
-      { name: "_from", type: "address" },
-      { name: "_to", type: "address" },
-      { name: "_value", type: "uint256" },
-    ],
-    name: "transferFrom",
-    outputs: [{ name: "success", type: "bool" }],
-    payable: false,
-    stateMutability: "nonpayable",
-    type: "function",
-  },
-  {
-    constant: true,
-    inputs: [],
-    name: "decimals",
-    outputs: [{ name: "", type: "uint8" }],
-    payable: false,
-    stateMutability: "view",
-    type: "function",
-  },
-  {
-    constant: false,
-    inputs: [{ name: "_value", type: "uint256" }],
-    name: "burn",
-    outputs: [{ name: "success", type: "bool" }],
-    payable: false,
-    stateMutability: "nonpayable",
-    type: "function",
-  },
-  {
-    constant: true,
-    inputs: [{ name: "", type: "address" }],
-    name: "balanceOf",
-    outputs: [{ name: "", type: "uint256" }],
-    payable: false,
-    stateMutability: "view",
-    type: "function",
-  },
-  {
-    constant: false,
-    inputs: [
-      { name: "_from", type: "address" },
-      { name: "_value", type: "uint256" },
-    ],
-    name: "burnFrom",
-    outputs: [{ name: "success", type: "bool" }],
-    payable: false,
-    stateMutability: "nonpayable",
-    type: "function",
-  },
-  {
-    constant: true,
-    inputs: [],
-    name: "symbol",
-    outputs: [{ name: "", type: "string" }],
-    payable: false,
-    stateMutability: "view",
-    type: "function",
-  },
-  {
-    constant: false,
-    inputs: [
-      { name: "_to", type: "address" },
-      { name: "_value", type: "uint256" },
-    ],
-    name: "transfer",
-    outputs: [],
-    payable: false,
-    stateMutability: "nonpayable",
-    type: "function",
-  },
-  {
-    constant: false,
-    inputs: [
-      { name: "_spender", type: "address" },
-      { name: "_value", type: "uint256" },
-      { name: "_extraData", type: "bytes" },
-    ],
-    name: "approveAndCall",
-    outputs: [{ name: "success", type: "bool" }],
-    payable: false,
-    stateMutability: "nonpayable",
-    type: "function",
-  },
-  {
-    constant: true,
-    inputs: [
-      { name: "", type: "address" },
-      { name: "", type: "address" },
-    ],
-    name: "allowance",
-    outputs: [{ name: "", type: "uint256" }],
-    payable: false,
-    stateMutability: "view",
-    type: "function",
-  },
-  {
-    inputs: [
-      { name: "initialSupply", type: "uint256" },
-      { name: "tokenName", type: "string" },
-      { name: "tokenSymbol", type: "string" },
-    ],
-    payable: false,
-    stateMutability: "nonpayable",
-    type: "constructor",
-  },
-  {
-    anonymous: false,
-    inputs: [
-      { indexed: true, name: "from", type: "address" },
-      { indexed: true, name: "to", type: "address" },
-      { indexed: false, name: "value", type: "uint256" },
-    ],
-    name: "Transfer",
-    type: "event",
-  },
-  {
-    anonymous: false,
-    inputs: [
-      { indexed: true, name: "from", type: "address" },
-      { indexed: false, name: "value", type: "uint256" },
-    ],
-    name: "Burn",
-    type: "event",
-  },
-];
diff --git a/src/configs/index.ts b/src/configs/index.ts
deleted file mode 100644
index 6d4bef9de..000000000
--- a/src/configs/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from "./strings";
-export * from "./abis";
-export * from "./ubiquibot-config-default";
diff --git a/src/configs/strings.ts b/src/configs/strings.ts
deleted file mode 100644
index 3f3128920..000000000
--- a/src/configs/strings.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export const GLOBAL_STRINGS = {
-  unassignComment: "Releasing the bounty back to dev pool because the allocated duration already ended!",
-  askUpdate: "Do you have any updates",
-  assignCommandDisabledComment: "The `/assign` command is disabled for this repository.",
-  skipPriceLabelGenerationComment: "Pricing is disabled on parent issues.",
-  ignoreStartCommandForParentIssueComment:
-    "Please select a child issue from the specification checklist to work on. The `/start` command is disabled on parent issues.",
-  autopayComment: "Automatic payment for this issue is enabled:",
-};
diff --git a/src/configs/ubiquibot-config-default.ts b/src/configs/ubiquibot-config-default.ts
deleted file mode 100644
index 9598ef782..000000000
--- a/src/configs/ubiquibot-config-default.ts
+++ /dev/null
@@ -1,115 +0,0 @@
-import { MergedConfig } from "../types";
-
-export const DefaultConfig: MergedConfig = {
-  evmNetworkId: 100,
-  priceMultiplier: 1,
-  issueCreatorMultiplier: 2,
-  paymentPermitMaxPrice: 9007199254740991,
-  maxConcurrentAssigns: 9007199254740991,
-  assistivePricing: false,
-  disableAnalytics: false,
-  commentIncentives: false,
-  registerWalletWithVerification: false,
-  promotionComment:
-    "\n
If you enjoy the DevPool experience, please follow Ubiquity on GitHub and star this repo to show your support. It helps a lot!
", - defaultLabels: [], - timeLabels: [ - { - name: "Time: <1 Hour", - }, - { - name: "Time: <1 Day", - }, - { - name: "Time: <1 Week", - }, - { - name: "Time: <2 Weeks", - }, - { - name: "Time: <1 Month", - }, - ], - priorityLabels: [ - { - name: "Priority: 1 (Normal)", - }, - { - name: "Priority: 2 (Medium)", - }, - { - name: "Priority: 3 (High)", - }, - { - name: "Priority: 4 (Urgent)", - }, - { - name: "Priority: 5 (Emergency)", - }, - ], - commandSettings: [ - { - name: "start", - enabled: false, - }, - { - name: "stop", - enabled: false, - }, - { - name: "wallet", - enabled: false, - }, - { - name: "payout", - enabled: false, - }, - { - name: "multiplier", - enabled: false, - }, - { - name: "query", - enabled: false, - }, - { - name: "ask", - enabled: false, - }, - { - name: "allow", - enabled: false, - }, - { - name: "autopay", - enabled: false, - }, - ], - incentives: { - comment: { - elements: {}, - totals: { - word: 0, - }, - }, - }, - enableAccessControl: { - label: false, - organization: true, - }, - staleBountyTime: "0d", - timeRangeForMaxIssue: 24, //24 - timeRangeForMaxIssueEnabled: false, - permitBaseUrl: "https://pay.ubq.fi", - botDelay: 100, // 100ms - followUpTime: "4 days", - disqualifyTime: "7 days", - newContributorGreeting: { - enabled: true, - header: - "Thank you for contributing to UbiquiBot! Please be sure to set your wallet address before completing your first bounty so that the automatic payout upon task completion will work for you.", - helpMenu: true, - footer: - "###### Also please star this repository and [@ubiquity/devpool-directory](https://github.com/ubiquity/devpool-directory/) to show your support. It helps a lot!", - }, -}; diff --git a/src/configs/weekly.ts b/src/configs/weekly.ts deleted file mode 100644 index b0ddb7f09..000000000 --- a/src/configs/weekly.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const weeklyConfig = { - remoteAsset: { - flat: { - remoteUrl: "https://example.org/flat.png", - isUsing: false, - }, - brand: { - remoteUrl: "https://example.org/brand.png", - isUsing: false, - }, - }, -}; diff --git a/src/handlers/access/index.ts b/src/handlers/access/index.ts deleted file mode 100644 index c540a8f9c..000000000 --- a/src/handlers/access/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./labels-access"; diff --git a/src/handlers/access/labels-access.ts b/src/handlers/access/labels-access.ts index 228aa5a38..44aaf8cf4 100644 --- a/src/handlers/access/labels-access.ts +++ b/src/handlers/access/labels-access.ts @@ -1,20 +1,23 @@ -import { getAccessLevel } from "../../adapters/supabase"; -import { getBotConfig, getBotContext, getLogger } from "../../bindings"; -import { addCommentToIssue, getUserPermission, removeLabel, addLabelToIssue } from "../../helpers"; -import { Payload } from "../../types"; - -export const handleLabelsAccess = async () => { - const { accessControl } = getBotConfig(); - if (!accessControl.label) return true; - - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; +import Runtime from "../../bindings/bot-runtime"; +import { isUserAdminOrBillingManager, addLabelToIssue, addCommentToIssue } from "../../helpers/issue"; +import { Context } from "../../types/context"; +import { UserType } from "../../types/payload"; + +export async function labelAccessPermissionsCheck(context: Context) { + const runtime = Runtime.getState(); + const { logger, payload } = context; + const { + features: { publicAccessControl }, + } = context.config; + if (!publicAccessControl.setLabel) return true; + if (!payload.issue) return; if (!payload.label?.name) return; + if (payload.sender.type === UserType.Bot) return true; + const sender = payload.sender.login; const repo = payload.repository; - const permissionLevel = await getUserPermission(sender, context); + const sufficientPrivileges = await isUserAdminOrBillingManager(context, sender); // event in plain english const eventName = payload.action === "labeled" ? "add" : "remove"; const labelName = payload.label.name; @@ -22,26 +25,58 @@ export const handleLabelsAccess = async () => { // get text before : const match = payload.label?.name?.split(":"); if (match.length == 0) return; - const label_type = match[0].toLowerCase(); - if (permissionLevel !== "admin") { - logger.info(`Getting ${label_type} access for ${sender} on ${repo.full_name}`); - // check permission - const accessible = await getAccessLevel(sender, repo.full_name, label_type); + const labelType = match[0].toLowerCase(); + if (sufficientPrivileges) { + logger.info("Admin and billing managers have full control over all labels", { + repo: repo.full_name, + user: sender, + labelType, + }); + return true; + } else { + logger.info("Checking access for labels", { repo: repo.full_name, user: sender, labelType }); + // check permission + const { access, user } = runtime.adapters.supabase; + const userId = await user.getUserId(context.event, sender); + const accessible = await access.getAccess(userId); if (accessible) { return true; } + console.trace({ "payload.action": payload.action }); + if (payload.action === "labeled") { // remove the label - await removeLabel(labelName); + await removeLabel(context, labelName); } else if (payload.action === "unlabeled") { // add the label - await addLabelToIssue(labelName); + await addLabelToIssue(context, labelName); } - await addCommentToIssue(`@${sender}, You are not allowed to ${eventName} ${labelName}`, payload.issue.number); - logger.info(`@${sender} is not allowed to ${eventName} ${labelName}`); + await addCommentToIssue( + context, + `@${sender}, You are not allowed to ${eventName} ${labelName}`, + payload.issue.number + ); + logger.info("No access to edit label", { sender, label: labelName }); return false; } - return true; -}; +} +async function removeLabel(context: Context, name: string) { + const payload = context.payload; + if (!payload.issue) { + context.logger.debug("Invalid issue object"); + return; + } + + try { + await context.octokit.issues.removeLabel({ + owner: payload.repository.owner.login, + repo: payload.repository.name, + issue_number: payload.issue.number, + name: name, + }); + } catch (e: unknown) { + context.logger.fatal("Removing label failed!", e); + } +} diff --git a/src/handlers/assign/action.ts b/src/handlers/assign/action.ts deleted file mode 100644 index d02d1589c..000000000 --- a/src/handlers/assign/action.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { getBotConfig, getBotContext, getLogger } from "../../bindings"; -import { addCommentToIssue, closePullRequest, calculateWeight, calculateDuration } from "../../helpers"; -import { gitLinkedPrParser } from "../../helpers/parser"; -import { Payload, LabelItem } from "../../types"; -import { deadLinePrefix } from "../shared"; - -const exclude_accounts: string[] = []; -export const commentWithAssignMessage = async (): Promise => { - const context = getBotContext(); - const config = getBotConfig(); - const logger = getLogger(); - const payload = context.payload as Payload; - if (!payload.issue) { - logger.debug(`Empty issue object`); - return; - } - - logger.info(`Commenting timeline message for issue: ${payload.issue.number}`); - - const _assignees = payload.issue?.assignees; - const assignees = _assignees ? _assignees?.filter((i) => !exclude_accounts.includes(i.login)) : []; - const existAssignees = assignees && assignees.length > 0; - if (!existAssignees) { - logger.debug(`No assignees for comment`); - return; - } - - const flattened_assignees = assignees.reduce((acc, cur) => `${acc} @${cur.login}`, ""); - - // get the time label from the `labels` - const labels = payload.issue?.labels; - if (!labels) { - logger.debug(`No labels to calculate timeline`); - return; - } - const timeLabelsDefined = config.price.timeLabels; - const timeLabelsAssigned: LabelItem[] = []; - for (const _label of labels) { - const _label_type = typeof _label; - const _label_name = _label_type === "string" ? _label.toString() : _label_type === "object" ? _label.name : "unknown"; - - const timeLabel = timeLabelsDefined.find((item) => item.name === _label_name); - if (timeLabel) { - timeLabelsAssigned.push(timeLabel); - } - } - - if (timeLabelsAssigned.length == 0) { - logger.debug(`No labels to calculate timeline`); - return; - } - - const sorted = timeLabelsAssigned.sort((a, b) => calculateWeight(a) - calculateWeight(b)); - const targetTimeLabel = sorted[0]; - const duration = calculateDuration(targetTimeLabel); - if (!duration) { - logger.debug(`Missing configure for timelabel: ${targetTimeLabel.name}`); - return; - } - - const currentDate = new Date(); - const currentDateInMilliseconds = currentDate.getTime(); - const endDate = new Date(currentDateInMilliseconds + duration * 1000); - const commitMessage = `${flattened_assignees} ${deadLinePrefix} ${endDate.toUTCString().replace("GMT", "UTC")}`; - logger.debug(`Creating an issue comment, commit_msg: ${commitMessage}`); - - await addCommentToIssue(commitMessage, payload.issue?.number); -}; - -export const closePullRequestForAnIssue = async (): Promise => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; - if (!payload.issue?.number) return; - - const prs = await gitLinkedPrParser({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - issue_number: payload.issue.number, - }); - - if (!prs.length) return; - - logger.info(`Opened prs for this issue: ${JSON.stringify(prs)}`); - let comment = `These linked pull requests are closed: `; - for (let i = 0; i < prs.length; i++) { - await closePullRequest(prs[i].prNumber); - comment += ` #${prs[i].prNumber} `; - } - await addCommentToIssue(comment, payload.issue.number); -}; diff --git a/src/handlers/assign/assign-command-handler.ts b/src/handlers/assign/assign-command-handler.ts new file mode 100644 index 000000000..7897880c6 --- /dev/null +++ b/src/handlers/assign/assign-command-handler.ts @@ -0,0 +1,115 @@ +import { getLinkedPullRequests } from "../../helpers/get-linked-pull-requests"; +import { calculateDurations, calculateLabelValue } from "../../helpers/shared"; +import { Context } from "../../types/context"; +import { Label } from "../../types/label"; +import { GitHubPayload } from "../../types/payload"; + +export async function assignCommandHandler(context: Context) { + const config = context.config; + const logger = context.logger; + const payload = context.event.payload as GitHubPayload; + if (!payload.issue) { + return logger.fatal("Issue is not defined"); + } + + const assignees = payload.issue.assignees; + + // If no valid assignees exist, log a debug message and return + if (assignees.length === 0) { + return logger.error("No assignees"); + } + + // Flatten assignees into a string + const flattenedAssignees = assignees.reduce((acc, assignee) => `${acc} @${assignee?.login}`, ""); + + // Extract labels from payload + const labels = payload.issue?.labels; + + // If no labels exist, log a debug message and return + if (!labels) { + return logger.error(`No labels to calculate timeline`); + } + + // Filter out labels that match the time labels defined in the config + const timeLabelsAssigned: Label[] = labels.filter((assignedLabel) => + typeof assignedLabel === "string" || typeof assignedLabel === "object" + ? config.labels.time.some((label) => label === assignedLabel.name) + : false + ); + + if (timeLabelsAssigned.length == 0) { + return logger.debug("No labels to calculate timeline"); + } + + // Sort labels by weight and select the one with the smallest weight + const sortedLabels = timeLabelsAssigned + .sort((a, b) => { + const fullLabelA = labels.find((label) => label.name === a.name)?.name; + const fullLabelB = labels.find((label) => label.name === b.name)?.name; + + if (!fullLabelA || !fullLabelB) { + return 0; // return a default value + } + + return calculateLabelValue(fullLabelA) - calculateLabelValue(fullLabelB); + }) + .map((label) => labels.find((fullLabel) => fullLabel.name === label.name)); + + // Filter out undefined values + const validSortedLabels = sortedLabels.filter((label) => label !== undefined); + + // Calculate the duration for the target label + const labelDuration = calculateDurations(validSortedLabels as Label[]); + const shortestDurationLabel = labelDuration[0]; + + // Calculate the end date based on the current date and the label duration + const currentDate = new Date(); + const endDate = new Date(currentDate.getTime() + shortestDurationLabel * 1000); + + // Format the comment + const comment = `${flattenedAssignees} the deadline is at ${endDate.toISOString()}`; + + // Add the comment to the issue + return comment; +} + +export async function closePullRequestForAnIssue(context: Context) { + const logger = context.logger; + const payload = context.event.payload as GitHubPayload; + if (!payload.issue?.number) { + throw logger.fatal("Issue is not defined"); + } + + const linkedPullRequests = await getLinkedPullRequests(context, { + owner: payload.repository.owner.login, + repository: payload.repository.name, + issue: payload.issue.number, + }); + + if (!linkedPullRequests.length) { + return logger.info(`No linked pull requests to close`); + } + + logger.info(`Opened prs`, linkedPullRequests); + let comment = `These linked pull requests are closed: `; + for (let i = 0; i < linkedPullRequests.length; i++) { + await closePullRequest(context, linkedPullRequests[i].number); + comment += ` #${linkedPullRequests[i].number} `; + } + return logger.info(comment); + // await addCommentToIssue(comment, payload.issue.number); +} + +async function closePullRequest(context: Context, pullNumber: number) { + const payload = context.payload as GitHubPayload; + try { + await context.octokit.rest.pulls.update({ + owner: payload.repository.owner.login, + repo: payload.repository.name, + pull_number: pullNumber, + state: "closed", + }); + } catch (err: unknown) { + context.logger.fatal("Closing pull requests failed!", err); + } +} diff --git a/src/handlers/assign/auto.ts b/src/handlers/assign/auto.ts deleted file mode 100644 index 380b59983..000000000 --- a/src/handlers/assign/auto.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { getBotContext, getLogger } from "../../bindings"; -import { addAssignees, getAllPullRequests, getIssueByNumber, getPullByNumber } from "../../helpers"; -import { gitLinkedIssueParser } from "../../helpers/parser"; -import { Payload } from "../../types"; - -// Check for pull requests linked to their respective issues but not assigned to them -export const checkPullRequests = async () => { - const context = getBotContext(); - const logger = getLogger(); - const pulls = await getAllPullRequests(context); - - if (pulls.length === 0) { - logger.debug(`No pull requests found at this time`); - return; - } - - const payload = context.payload as Payload; - - // Loop through the pull requests and assign them to their respective issues if needed - for (const pull of pulls) { - const linkedIssue = await gitLinkedIssueParser({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - pull_number: pull.number, - }); - - // if pullRequestLinked is empty, continue - if (linkedIssue == "" || !pull.user || !linkedIssue) { - continue; - } - - const connectedPull = await getPullByNumber(context, pull.number); - - // Newly created PULL (draft or direct) pull does have same `created_at` and `updated_at`. - if (connectedPull?.created_at !== connectedPull?.updated_at) { - logger.debug("It's an updated Pull Request, reverting"); - continue; - } - - const linkedIssueNumber = linkedIssue.substring(linkedIssue.lastIndexOf("/") + 1); - - // Check if the pull request opener is assigned to the issue - const opener = pull.user.login; - - const issue = await getIssueByNumber(context, +linkedIssueNumber); - if (!issue?.assignees) continue; - - // if issue is already assigned, continue - if (issue.assignees.length > 0) { - logger.debug(`Issue already assigned, ignoring...`); - continue; - } - - const assignedUsernames = issue.assignees.map((assignee) => assignee.login); - if (!assignedUsernames.includes(opener)) { - await addAssignees(+linkedIssueNumber, [opener]); - logger.debug(`Assigned pull request #${pull.number} opener to issue ${linkedIssueNumber}.`); - } - } -}; diff --git a/src/handlers/assign/check-pull-requests.ts b/src/handlers/assign/check-pull-requests.ts new file mode 100644 index 000000000..4625aedd4 --- /dev/null +++ b/src/handlers/assign/check-pull-requests.ts @@ -0,0 +1,112 @@ +import axios from "axios"; +import { HTMLElement, parse } from "node-html-parser"; +import { getAllPullRequests, addAssignees } from "../../helpers/issue"; +import { Context } from "../../types/context"; + +// Check for pull requests linked to their respective issues but not assigned to them +export async function checkPullRequests(context: Context) { + const { logger, payload } = context; + const pulls = await getAllPullRequests(context); + + if (pulls.length === 0) { + return logger.debug(`No pull requests found at this time`); + } + + // Loop through the pull requests and assign them to their respective issues if needed + for (const pull of pulls) { + const linkedIssue = await getLinkedIssues({ + owner: payload.repository.owner.login, + repository: payload.repository.name, + pull: pull.number, + }); + + // if pullRequestLinked is empty, continue + if (linkedIssue == null || !pull.user || !linkedIssue) { + continue; + } + + const connectedPull = await getPullByNumber(context, pull.number); + + // Newly created PULL (draft or direct) pull does have same `created_at` and `updated_at`. + if (connectedPull?.created_at !== connectedPull?.updated_at) { + logger.debug("It's an updated Pull Request, reverting"); + continue; + } + + const linkedIssueNumber = linkedIssue.substring(linkedIssue.lastIndexOf("/") + 1); + + // Check if the pull request opener is assigned to the issue + const opener = pull.user.login; + + const issue = await getIssueByNumber(context, +linkedIssueNumber); + if (!issue?.assignees) continue; + + // if issue is already assigned, continue + if (issue.assignees.length > 0) { + logger.debug(`Issue already assigned, ignoring...`); + continue; + } + + const assignedUsernames = issue.assignees.map((assignee) => assignee.login); + if (!assignedUsernames.includes(opener)) { + await addAssignees(context, +linkedIssueNumber, [opener]); + logger.debug("Assigned pull request opener to issue", { + pullRequest: pull.number, + issue: linkedIssueNumber, + opener, + }); + } + } + return logger.debug(`Checking pull requests done!`); +} + +export async function getLinkedIssues({ owner, repository, pull }: GetLinkedParams) { + const { data } = await axios.get(`https://github.com/${owner}/${repository}/pull/${pull}`); + const dom = parse(data); + const devForm = dom.querySelector("[data-target='create-branch.developmentForm']") as HTMLElement; + const linkedIssues = devForm.querySelectorAll(".my-1"); + + if (linkedIssues.length === 0) { + return null; + } + + const issueUrl = linkedIssues[0].querySelector("a")?.attrs?.href || null; + return issueUrl; +} + +export async function getPullByNumber(context: Context, pull: number) { + const payload = context.payload; + + try { + const response = await context.octokit.rest.pulls.get({ + owner: payload.repository.owner.login, + repo: payload.repository.name, + pull_number: pull, + }); + return response.data; + } catch (err: unknown) { + context.logger.fatal("Fetching pull request failed!", err); + return; + } +} +// Get issues by issue number +export async function getIssueByNumber(context: Context, issueNumber: number) { + const payload = context.payload; + try { + const { data: issue } = await context.octokit.rest.issues.get({ + owner: payload.repository.owner.login, + repo: payload.repository.name, + issue_number: issueNumber, + }); + return issue; + } catch (e: unknown) { + context.logger.fatal("Fetching issue failed!", e); + return; + } +} +export interface GetLinkedParams { + owner: string; + repository: string; + issue?: number; + pull?: number; +} diff --git a/src/handlers/assign/index.ts b/src/handlers/assign/index.ts deleted file mode 100644 index 30697c06e..000000000 --- a/src/handlers/assign/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./action"; diff --git a/src/handlers/comment/action.ts b/src/handlers/comment/action.ts deleted file mode 100644 index 60ea5bbae..000000000 --- a/src/handlers/comment/action.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { getBotConfig, getBotContext, getLogger } from "../../bindings"; -import { Payload } from "../../types"; -import { ErrorDiff } from "../../utils/helpers"; -import { IssueCommentCommands } from "./commands"; -import { commentParser, userCommands } from "./handlers"; -import { verifyFirstCheck } from "./handlers/first"; - -export const handleComment = async (): Promise => { - const context = getBotContext(); - const config = getBotConfig(); - const logger = getLogger(); - const payload = context.payload as Payload; - - logger.info(`Handling an issue comment on issue ${payload.issue?.number}`); - const comment = payload.comment; - if (!comment) { - logger.info(`Comment is null. Skipping`); - return; - } - - const body = comment.body; - const commentedCommands = commentParser(body); - - if (commentedCommands.length === 0) { - await verifyFirstCheck(); - return; - } - - const allCommands = userCommands(); - for (const command of commentedCommands) { - const userCommand = allCommands.find((i) => i.id == command); - - if (userCommand) { - const { id, handler, callback, successComment, failureComment } = userCommand; - logger.info(`Running a comment handler: ${handler.name}`); - - const { payload: _payload } = getBotContext(); - const issue = (_payload as Payload).issue; - if (!issue) continue; - - const feature = config.command.find((e) => e.name === id.split("/")[1]); - - if (!feature?.enabled && id !== IssueCommentCommands.HELP) { - logger.info(`Skipping '${id}' because it is disabled on this repo.`); - await callback(issue.number, `Skipping \`${id}\` because it is disabled on this repo.`, payload.action, payload.comment); - continue; - } - - try { - const response = await handler(body); - const callbackComment = response ?? successComment ?? ""; - if (callbackComment) await callback(issue.number, callbackComment, payload.action, payload.comment); - } catch (err: unknown) { - // Use failureComment for failed command if it is available - if (failureComment) { - await callback(issue.number, failureComment, payload.action, payload.comment); - } - await callback(issue.number, ErrorDiff(err), payload.action, payload.comment); - } - } else { - logger.info(`Skipping for a command: ${command}`); - } - } -}; diff --git a/src/handlers/comment/commands.ts b/src/handlers/comment/commands.ts deleted file mode 100644 index 9bce9fc6e..000000000 --- a/src/handlers/comment/commands.ts +++ /dev/null @@ -1,15 +0,0 @@ -export enum IssueCommentCommands { - HELP = "/help", // list available commands - START = "/start", // assign the hunter to the issue automatically - STOP = "/stop", // unassign to default - WALLET = "/wallet", // register wallet address - PAYOUT = "/payout", // request permit payout - MULTIPLIER = "/multiplier", // set bounty multiplier (for treasury) - QUERY = "/query", - ASK = "/ask", // ask GPT a question - // Access Controls - - ALLOW = "/allow", - AUTOPAY = "/autopay", - AUTHORIZE = "/authorize", -} diff --git a/src/handlers/comment/comment-created.ts b/src/handlers/comment/comment-created.ts new file mode 100644 index 000000000..6db717bbe --- /dev/null +++ b/src/handlers/comment/comment-created.ts @@ -0,0 +1,48 @@ +import { Context } from "../../types/context"; +import { GitHubComment, GitHubPayload } from "../../types/payload"; +import { commentParser, userCommands } from "./handlers/comment-handler-main"; +import { verifyFirstCommentInRepository } from "./handlers/first"; + +export async function commentCreated(context: Context) { + const config = context.config, + logger = context.logger, + payload = context.event.payload as GitHubPayload; + + const comment = payload.comment as GitHubComment; + + const body = comment.body; + const commentedCommand = commentParser(body); + + if (!comment) { + logger.info(`Comment is null. Skipping`); + } + const issue = payload.issue; + if (!issue) { + throw logger.error("Issue is null. Skipping", { issue }); + } + + if (commentedCommand) { + await verifyFirstCommentInRepository(context); + } + + const allCommands = userCommands(config.miscellaneous.registerWalletWithVerification); + const userCommand = allCommands.find((i) => i.id == commentedCommand); + + if (userCommand) { + const { id, handler } = userCommand; + logger.info("Running a comment handler", { id, handler: handler.name }); + + const isDisabled = config.disabledCommands.some((command) => command === id.replace("/", "")); + + if (isDisabled && id !== "/help") { + return logger.error("Skipping because it is disabled on this repo.", { id }); + } + + return await handler(context, body); + } else { + const sanitizedBody = body.replace(//g, ""); + return logger.verbose("Comment event received without a recognized user command.", { + sanitizedBody, + }); + } +} diff --git a/src/handlers/comment/handlers/allow.ts b/src/handlers/comment/handlers/allow.ts deleted file mode 100644 index aa867985c..000000000 --- a/src/handlers/comment/handlers/allow.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { upsertAccessControl } from "../../../adapters/supabase"; -import { getBotContext, getLogger } from "../../../bindings"; -import { getUserPermission } from "../../../helpers"; -import { Payload } from "../../../types"; - -export const setAccess = async (body: string) => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; - const sender = payload.sender.login; - - const validAccessString = ["priority", "time", "price", "multiplier"]; - - logger.info(`Received '/allow' command from user: ${sender}`); - - const issue = payload.issue; - const repo = payload.repository; - if (!issue) { - logger.info(`Skipping '/allow' because of no issue instance`); - return; - } - - const regex = /\/allow\s+(\S+)\s+(\S+)\s+(\S+)/; - const matches = body.match(regex); - - if (matches) { - let accessType, username, bool; - matches.slice(1).forEach((part) => { - if (part.startsWith("@")) username = part.slice(1); - else if (part.startsWith("set-")) accessType = part.slice(4); - else if (part === "true" || part === "false") bool = part; - }); - if (!accessType || !username || !bool) { - logger.error("Invalid body for allow command"); - return `Invalid syntax for allow \n usage: '/allow set-(access type) @user true|false' \n ex-1 /allow set-multiplier @user false`; - } - // Check if access control demand is valid - if (!validAccessString.includes(accessType)) { - logger.info(`Access control setting for ${accessType} does not exist.`); - return `Access control setting for ${accessType} does not exist.`; - } - - // check if sender is admin - // passing in context so we don't have to make another request to get the user - const permissionLevel = await getUserPermission(sender, context); - - // if sender is not admin, return - if (permissionLevel !== "admin") { - logger.info(`User ${sender} is not an admin`); - return `You are not an admin and do not have the required permissions to access this function.`; - } - - // convert accessType to valid table - const tableName = `${accessType}_access`; - - await upsertAccessControl(username, repo.full_name, tableName, bool === "true"); - return `Updated access for @${username} successfully!\t Access: **${accessType}** for "${repo.full_name}"`; - } else { - logger.error("Invalid body for allow command"); - return `Invalid syntax for allow \n usage: '/allow set-(access type) @user true|false' \n ex-1 /allow set-multiplier @user false`; - } -}; diff --git a/src/handlers/comment/handlers/ask.ts b/src/handlers/comment/handlers/ask.ts index 63777d4ae..7af2d94f6 100644 --- a/src/handlers/comment/handlers/ask.ts +++ b/src/handlers/comment/handlers/ask.ts @@ -1,18 +1,15 @@ -import { getBotContext, getLogger } from "../../../bindings"; -import { Payload, StreamlinedComment, UserType } from "../../../types"; -import { getAllIssueComments, getAllLinkedIssuesAndPullsInBody } from "../../../helpers"; import { CreateChatCompletionRequestMessage } from "openai/resources/chat"; -import { askGPT, decideContextGPT, sysMsg } from "../../../helpers/gpt"; -import { ErrorDiff } from "../../../utils/helpers"; +import { getAllIssueComments } from "../../../helpers/issue"; +import { Context } from "../../../types/context"; +import { StreamlinedComment } from "../../../types/openai"; +import { GitHubPayload, UserType } from "../../../types/payload"; +import { askGPT, decideContextGPT, getAllLinkedIssuesAndPullsInBody, sysMsg } from "./ask/ask-gpt"; -/** - * @param body The question to ask - */ -export const ask = async (body: string) => { - const context = getBotContext(); - const logger = getLogger(); +export async function ask(context: Context, body: string) { + // The question to ask + const logger = context.logger; - const payload = context.payload as Payload; + const payload = context.event.payload as GitHubPayload; const sender = payload.sender.login; const issue = payload.issue; @@ -21,7 +18,7 @@ export const ask = async (body: string) => { } if (!issue) { - return `This command can only be used on issues`; + return `This command can only be used on issues and pull requests`; } const chatHistory: CreateChatCompletionRequestMessage[] = []; @@ -36,13 +33,12 @@ export const ask = async (body: string) => { const [, body] = matches; // standard comments - const comments = await getAllIssueComments(issue.number); - // raw so we can grab the tag - const commentsRaw = await getAllIssueComments(issue.number, "raw"); + const comments = await getAllIssueComments(context, issue.number); + // raw so we can grab the tag + const commentsRaw = await getAllIssueComments(context, issue.number, "raw"); if (!comments) { - logger.info(`Error getting issue comments`); - return ErrorDiff(`Error getting issue comments`); + throw logger.fatal(`Error getting issue comments`); } // add the first comment of the issue/pull request @@ -53,7 +49,7 @@ export const ask = async (body: string) => { // add the rest comments.forEach(async (comment, i) => { - if (comment.user.type == UserType.User || commentsRaw[i].body.includes("")) { + if (comment.user.type == UserType.User || commentsRaw[i].body.includes("")) { streamlined.push({ login: comment.user.login, body: comment.body, @@ -62,17 +58,23 @@ export const ask = async (body: string) => { }); // returns the conversational context from all linked issues and prs - const links = await getAllLinkedIssuesAndPullsInBody(issue.number); + const links = await getAllLinkedIssuesAndPullsInBody(context, issue.number); if (typeof links === "string") { - logger.info(`Error getting linked issues or prs: ${links}`); + logger.info("Error getting linked issues or prs: ", links); } else { linkedIssueStreamlined = links.linkedIssues; linkedPRStreamlined = links.linkedPrs; } // let chatgpt deduce what is the most relevant context - const gptDecidedContext = await decideContextGPT(chatHistory, streamlined, linkedPRStreamlined, linkedIssueStreamlined); + const gptDecidedContext = await decideContextGPT( + context, + chatHistory, + streamlined, + linkedPRStreamlined, + linkedIssueStreamlined + ); if (linkedIssueStreamlined.length == 0 && linkedPRStreamlined.length == 0) { // No external context to add @@ -80,7 +82,7 @@ export const ask = async (body: string) => { { role: "system", content: sysMsg, - name: "UbiquityAI", + name: "UbiquiBot", } as CreateChatCompletionRequestMessage, { role: "user", @@ -92,32 +94,32 @@ export const ask = async (body: string) => { chatHistory.push( { role: "system", - content: sysMsg, // provide the answer template - name: "UbiquityAI", + content: sysMsg, + name: "UbiquiBot", } as CreateChatCompletionRequestMessage, { role: "system", - content: "Original Context: " + JSON.stringify(gptDecidedContext), // provide the context + content: "Original Context: " + JSON.stringify(gptDecidedContext), name: "system", } as CreateChatCompletionRequestMessage, { role: "user", - content: "Question: " + JSON.stringify(body), // provide the question + content: "Question: " + JSON.stringify(body), name: "user", } as CreateChatCompletionRequestMessage ); } - const gptResponse = await askGPT(body, chatHistory); + const gptResponse = await askGPT(context, chatHistory); if (typeof gptResponse === "string") { return gptResponse; } else if (gptResponse.answer) { return gptResponse.answer; } else { - return ErrorDiff(`Error getting response from GPT`); + throw logger.fatal("Error getting response from OpenAI"); } } else { - return "Invalid syntax for ask \n usage: '/ask What is pi?"; + return logger.error("Invalid syntax for ask. usage: '/ask What is pi?'"); } -}; +} diff --git a/src/handlers/comment/handlers/ask/ask-gpt.ts b/src/handlers/comment/handlers/ask/ask-gpt.ts new file mode 100644 index 000000000..130b1bb2f --- /dev/null +++ b/src/handlers/comment/handlers/ask/ask-gpt.ts @@ -0,0 +1,277 @@ +import OpenAI from "openai"; +import { CreateChatCompletionRequestMessage } from "openai/resources/chat"; +import { getAllIssueComments } from "../../../../helpers/issue"; +import { Context } from "../../../../types/context"; +import { StreamlinedComment } from "../../../../types/openai"; +import { GitHubPayload, UserType } from "../../../../types/payload"; +import { getIssueByNumber, getPullByNumber } from "../../../assign/check-pull-requests"; + +export const sysMsg = `You are the UbiquiBot, designed to provide accurate technical answers. \n +Whenever appropriate, format your response using GitHub Flavored Markdown. Utilize tables, lists, and code blocks for clear and organized answers. \n +Do not make up answers. If you are unsure, say so. \n +Original Context exists only to provide you with additional information to the current question, use it to formulate answers. \n +Infer the context of the question from the Original Context using your best judgement. \n +All replies MUST end with "\n\n ".\n +`; + +// export const gptContextTemplate = ` +// You are the UbiquiBot, designed to review and analyze pull requests. +// You have been provided with the spec of the issue and all linked issues or pull requests. +// Using this full context, Reply in pure JSON format, with the following structure omitting irrelevant information pertaining to the specification. +// You MUST provide the following structure, but you may add additional information if you deem it relevant. +// Example:[ +// { +// "source": "issue #123" +// "spec": "This is the issue spec" +// "relevant": [ +// { +// "login": "user", +// "body": "This is the relevant context" +// "relevancy": "Why is this relevant to the spec?" +// }, +// { +// "login": "other_user", +// "body": "This is other relevant context" +// "relevancy": "Why is this relevant to the spec?" +// } +// ] +// }, +// { +// "source": "Pull #456" +// "spec": "This is the pull request spec" +// "relevant": [ +// { +// "login": "user", +// "body": "This is the relevant context" +// "relevancy": "Why is this relevant to the spec?" +// }, +// { +// "login": "other_user", +// "body": "This is other relevant context" +// "relevancy": "Why is this relevant to the spec?" +// } +// ] +// } +// ] +// `; + +// best used alongside getAllLinkedIssuesAndPullsInBody() in helpers/issue +export async function decideContextGPT( + context: Context, + chatHistory: CreateChatCompletionRequestMessage[], + streamlined: StreamlinedComment[], + linkedPRStreamlined: StreamlinedComment[], + linkedIssueStreamlined: StreamlinedComment[] +) { + const logger = context.logger; + + const payload = context.event.payload as GitHubPayload; + const issue = payload.issue; + + if (!issue) { + return `Payload issue is undefined`; + } + + // standard comments + const comments = await getAllIssueComments(context, issue.number); + // raw so we can grab the tag + const commentsRaw = await getAllIssueComments(context, issue.number, "raw"); + + if (!comments) { + logger.info(`Error getting issue comments`); + return `Error getting issue comments`; + } + + // add the first comment of the issue/pull request + streamlined.push({ + login: issue.user.login, + body: issue.body, + }); + + // add the rest + comments.forEach(async (comment, i) => { + if (comment.user.type == UserType.User || commentsRaw[i].body.includes("")) { + streamlined.push({ + login: comment.user.login, + body: comment.body, + }); + } + }); + + // returns the conversational context from all linked issues and prs + const links = await getAllLinkedIssuesAndPullsInBody(context, issue.number); + + if (typeof links === "string") { + return logger.info("Error getting linked issues or prs: ", { links }); + } + + linkedIssueStreamlined = links.linkedIssues; + linkedPRStreamlined = links.linkedPrs; + + chatHistory.push( + { + role: "system", + content: "This issue/Pr context: \n" + JSON.stringify(streamlined), + name: "UbiquiBot", + } as CreateChatCompletionRequestMessage, + { + role: "system", + content: "Linked issue(s) context: \n" + JSON.stringify(linkedIssueStreamlined), + name: "UbiquiBot", + } as CreateChatCompletionRequestMessage, + { + role: "system", + content: "Linked Pr(s) context: \n" + JSON.stringify(linkedPRStreamlined), + name: "UbiquiBot", + } as CreateChatCompletionRequestMessage + ); + + // we'll use the first response to determine the context of future calls + const res = await askGPT(context, chatHistory); + + return res; +} + +export async function askGPT(context: Context, chatHistory: CreateChatCompletionRequestMessage[]) { + // base askGPT function + const logger = context.logger; + const config = context.config; + const { keys } = config; + + if (!keys.openAi) { + throw logger.fatal( + "You must configure the `openai-api-key` property in the bot configuration in order to use AI powered features." + ); + } + + const openAI = new OpenAI({ + apiKey: keys.openAi, + }); + + const res: OpenAI.Chat.Completions.ChatCompletion = await openAI.chat.completions.create({ + messages: chatHistory, + model: "gpt-3.5-turbo-16k", + max_tokens: config.miscellaneous.openAiTokenLimit, + temperature: 0, + }); + + const answer = res.choices[0].message.content; + + const tokenUsage = { + output: res.usage?.completion_tokens, + input: res.usage?.prompt_tokens, + total: res.usage?.total_tokens, + }; + + if (!res) { + throw context.logger.fatal("Error getting GPT response", { res }); + } + + return { answer, tokenUsage }; +} + +// Strips out all links from the body of an issue or pull request and fetches the conversational context from each linked issue or pull request +export async function getAllLinkedIssuesAndPullsInBody(context: Context, issueNumber: number) { + const logger = context.logger; + + const issue = await getIssueByNumber(context, issueNumber); + + if (!issue) { + throw logger.fatal("No issue found!", { issueNumber }); + } + + if (!issue.body) { + throw logger.fatal("No body found!", { issueNumber }); + } + + const body = issue.body; + const linkedPRStreamlined: StreamlinedComment[] = []; + const linkedIssueStreamlined: StreamlinedComment[] = []; + + const regex = /https:\/\/github\.com\/[^/\s]+\/[^/\s]+\/(issues|pull)\/(\d+)/gi; + const matches = body.match(regex); + + if (matches) { + const linkedIssues: number[] = []; + const linkedPrs: number[] = []; + + // this finds refs via all patterns: #, full url or [#25](url.to.issue) + const issueRef = issue.body.match(/(#(\d+)|https:\/\/github\.com\/[^/\s]+\/[^/\s]+\/(issues|pull)\/(\d+))/gi); + + // if they exist, strip out the # or the url and push them to their arrays + if (issueRef) { + issueRef.forEach((issue) => { + if (issue.includes("#")) { + linkedIssues.push(Number(issue.slice(1))); + } else { + if (issue.split("/")[5] == "pull") { + linkedPrs.push(Number(issue.split("/")[6])); + } else linkedIssues.push(Number(issue.split("/")[6])); + } + }); + } else { + logger.info(`No linked issues or prs found`); + } + + if (linkedPrs.length > 0) { + for (let i = 0; i < linkedPrs.length; i++) { + const pr = await getPullByNumber(context, linkedPrs[i]); + if (pr) { + linkedPRStreamlined.push({ + login: "system", + body: `=============== Pull Request #${pr.number}: ${pr.title} + ===============\n ${pr.body}}`, + }); + const prComments = await getAllIssueComments(context, linkedPrs[i]); + const prCommentsRaw = await getAllIssueComments(context, linkedPrs[i], "raw"); + prComments.forEach(async (comment, i) => { + if ( + comment.user.type == UserType.User || + prCommentsRaw[i].body.includes("") + ) { + linkedPRStreamlined.push({ + login: comment.user.login, + body: comment.body, + }); + } + }); + } + } + } + + if (linkedIssues.length > 0) { + for (let i = 0; i < linkedIssues.length; i++) { + const issue = await getIssueByNumber(context, linkedIssues[i]); + if (issue) { + linkedIssueStreamlined.push({ + login: "system", + body: `=============== Issue #${issue.number}: ${issue.title} + ===============\n ${issue.body} `, + }); + const issueComments = await getAllIssueComments(context, linkedIssues[i]); + const issueCommentsRaw = await getAllIssueComments(context, linkedIssues[i], "raw"); + issueComments.forEach(async (comment, i) => { + if ( + comment.user.type == UserType.User || + issueCommentsRaw[i].body.includes("") + ) { + linkedIssueStreamlined.push({ + login: comment.user.login, + body: comment.body, + }); + } + }); + } + } + } + + return { + linkedIssues: linkedIssueStreamlined, + linkedPrs: linkedPRStreamlined, + }; + } else { + logger.info(`No matches found`); + return { + linkedIssues: [], + linkedPrs: [], + }; + } +} diff --git a/src/handlers/comment/handlers/assign.ts b/src/handlers/comment/handlers/assign.ts deleted file mode 100644 index d4ab030ef..000000000 --- a/src/handlers/comment/handlers/assign.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { addAssignees, getAssignedIssues, getAvailableOpenedPullRequests, getAllIssueComments, calculateWeight, calculateDuration } from "../../../helpers"; -import { getBotConfig, getBotContext, getLogger } from "../../../bindings"; -import { Payload, LabelItem, Comment, IssueType, Issue } from "../../../types"; -import { deadLinePrefix } from "../../shared"; -import { getWalletAddress, getWalletMultiplier } from "../../../adapters/supabase"; -import { tableComment } from "./table"; -import { bountyInfo } from "../../wildcard"; -import { GLOBAL_STRINGS } from "../../../configs"; -import { isParentIssue } from "../../pricing"; - -export const assign = async (body: string) => { - const { payload: _payload } = getBotContext(); - const logger = getLogger(); - const config = getBotConfig(); - - const payload = _payload as Payload; - const { repository, organization } = payload; - - const id = organization?.id || repository?.id; // repository?.id as fallback - - const staleBounty = config.assign.staleBountyTime; - const startEnabled = config.command.find((command) => command.name === "start"); - - logger.info(`Received '/start' command from user: ${payload.sender.login}, body: ${body}`); - const issue = (_payload as Payload).issue; - - if (!issue) { - logger.info(`Skipping '/start' because of no issue instance`); - return "Skipping '/start' because of no issue instance"; - } - - if (!startEnabled?.enabled) { - logger.info(`Ignore '/start' command from user: ASSIGN_COMMAND_ENABLED config is set false`); - return GLOBAL_STRINGS.assignCommandDisabledComment; - } - - if (issue.body && isParentIssue(issue.body)) { - logger.info(`Ignore '/start' command from user: identified as parent issue`); - return GLOBAL_STRINGS.ignoreStartCommandForParentIssueComment; - } - - const openedPullRequests = await getAvailableOpenedPullRequests(payload.sender.login); - logger.info(`Opened Pull Requests with approved reviews or with no reviews but over 24 hours have passed: ${JSON.stringify(openedPullRequests)}`); - - const assignedIssues = await getAssignedIssues(payload.sender.login); - logger.info(`Max issue allowed is ${config.assign.bountyHunterMax}`); - - // check for max and enforce max - if (assignedIssues.length - openedPullRequests.length >= config.assign.bountyHunterMax) { - return `Too many assigned issues, you have reached your max of ${config.assign.bountyHunterMax}`; - } - - if (issue.state == IssueType.CLOSED) { - logger.info("Skipping '/start', reason: closed "); - return "Skipping `/start` since the issue is closed"; - } - const _assignees = payload.issue?.assignees; - const assignees = _assignees ?? []; - - if (assignees.length !== 0) { - logger.info(`Skipping '/start', reason: already assigned. assignees: ${assignees.length > 0 ? assignees.map((i) => i.login).join() : "NoAssignee"}`); - return "Skipping `/start` since the issue is already assigned"; - } - - // get the time label from the `labels` - const labels = payload.issue?.labels; - if (!labels) { - logger.info(`No labels to calculate timeline`); - return "Skipping `/start` since no issue labels are set to calculate the timeline"; - } - const timeLabelsDefined = config.price.timeLabels; - const timeLabelsAssigned: LabelItem[] = []; - for (const _label of labels) { - const _labelType = typeof _label; - const _labelName = _labelType === "string" ? _label.toString() : _labelType === "object" ? _label.name : "unknown"; - - const timeLabel = timeLabelsDefined.find((item) => item.name === _labelName); - if (timeLabel) { - timeLabelsAssigned.push(timeLabel); - } - } - - if (timeLabelsAssigned.length == 0) { - logger.info(`No time labels to calculate timeline`); - return "Skipping `/start` since no time labels are set to calculate the timeline"; - } - - const sorted = timeLabelsAssigned.sort((a, b) => calculateWeight(a) - calculateWeight(b)); - const targetTimeLabel = sorted[0]; - const duration = calculateDuration(targetTimeLabel); - if (!duration) { - logger.info(`Missing configure for time label: ${targetTimeLabel.name}`); - return "Skipping `/start` since configuration is missing for the following labels"; - } - - const startTime = new Date().getTime(); - const endTime = new Date(startTime + duration * 1000); - - const comment = { - deadline: endTime.toUTCString().replace("GMT", "UTC"), - wallet: (await getWalletAddress(payload.sender.login)) || "Please set your wallet address to use `/wallet 0x0000...0000`", - commit: `@${payload.sender.login} ${deadLinePrefix} ${endTime.toUTCString()}`, - tips: `
Tips:
-
    -
  • Use /wallet 0x0000...0000 if you want to update your registered payment wallet address @${payload.sender.login}.
  • -
  • Be sure to open a draft pull request as soon as possible to communicate updates on your progress.
  • -
  • Be sure to provide timely updates to us when requested, or you will be automatically unassigned from the bounty.
  • -
      `, - }; - - if (!assignees.map((i) => i.login).includes(payload.sender.login)) { - logger.info(`Adding the assignee: ${payload.sender.login}`); - await addAssignees(issue.number, [payload.sender.login]); - } - - let days: number | undefined; - let staleToDays: number | undefined; - let isBountyStale = false; - - if (staleBounty !== 0) { - days = Math.floor((new Date().getTime() - new Date(issue.created_at).getTime()) / (1000 * 60 * 60 * 24)); - staleToDays = Math.floor(staleBounty / (1000 * 60 * 60 * 24)); - isBountyStale = days >= staleToDays; - } - - // double check whether the assign message has been already posted or not - logger.info(`Creating an issue comment: ${comment.commit}`); - const issueComments = await getAllIssueComments(issue.number); - const comments = issueComments.sort((a: Comment, b: Comment) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()); - const latestComment = comments.length > 0 ? comments[0].body : undefined; - if (latestComment && comment.commit != latestComment) { - const { multiplier, reason, bounty } = await getMultiplierInfoToDisplay(payload.sender.login, id?.toString(), issue); - return tableComment({ ...comment, multiplier, reason, bounty, isBountyStale, days }) + comment.tips; - } - return; -}; - -const getMultiplierInfoToDisplay = async (senderLogin: string, org_id: string, issue: Issue) => { - const { reason, value } = await getWalletMultiplier(senderLogin, org_id); - - const multiplier = value?.toFixed(2) || "1.00"; - - let _multiplierToDisplay, _reasonToDisplay, _bountyToDisplay; - - if (value == 1) { - if (reason) { - _multiplierToDisplay = multiplier; - _reasonToDisplay = reason; - } else { - // default mode: normal bounty hunter with default multiplier 1 and no reason - // nothing to show about multiplier - } - } else { - _multiplierToDisplay = multiplier; - _reasonToDisplay = reason; - _bountyToDisplay = `Permit generation disabled because price label is not set.`; - const issueDetailed = bountyInfo(issue); - if (issueDetailed.priceLabel) { - _bountyToDisplay = (+issueDetailed.priceLabel.substring(7, issueDetailed.priceLabel.length - 4) * value).toString() + " USD"; - } - } - return { multiplier: _multiplierToDisplay, reason: _reasonToDisplay, bounty: _bountyToDisplay }; -}; diff --git a/src/handlers/comment/handlers/authorize.ts b/src/handlers/comment/handlers/authorize.ts index 03918cded..180fa9ace 100644 --- a/src/handlers/comment/handlers/authorize.ts +++ b/src/handlers/comment/handlers/authorize.ts @@ -1,45 +1,51 @@ -import { _approveLabelChange, getLabelChanges } from "../../../adapters/supabase"; -import { getBotContext, getLogger } from "../../../bindings"; -import { getUserPermission } from "../../../helpers"; -import { Payload } from "../../../types"; -import { ErrorDiff } from "../../../utils/helpers"; -import { bountyInfo } from "../../wildcard"; - -export const approveLabelChange = async () => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; +import Runtime from "../../../bindings/bot-runtime"; +import { isUserAdminOrBillingManager } from "../../../helpers/issue"; +import { Context } from "../../../types/context"; +import { GitHubPayload } from "../../../types/payload"; +import { taskPaymentMetaData } from "../../wildcard/analytics"; + +export async function authorizeLabelChanges(context: Context) { + const runtime = Runtime.getState(); + const { label } = runtime.adapters.supabase; + const logger = context.logger; + const payload = context.event.payload as GitHubPayload; const sender = payload.sender.login; - logger.info(`Received '/authorize' command from user: ${sender}`); + logger.info("Running '/authorize' command handler", { sender }); const { issue, repository } = payload; if (!issue) { - logger.info(`Skipping '/authorize' because of no issue instance`); - return; + return logger.info(`Skipping '/authorize' because of no issue instance`); } // check if sender is admin // passing in context so we don't have to make another request to get the user - const permissionLevel = await getUserPermission(sender, context); + const sufficientPrivileges = await isUserAdminOrBillingManager(context, sender); // if sender is not admin, return - if (permissionLevel !== "admin" && permissionLevel !== "billing_manager") { - logger.info(`User ${sender} is not an admin/billing_manager`); - return ErrorDiff(`You are not an admin/billing_manager and do not have the required permissions to access this function.`); + if (sufficientPrivileges) { + throw logger.fatal( + "User is not an admin/billing_manager and do not have the required permissions to access this function.", + { sender } + ); } - const issueDetailed = bountyInfo(issue); + const task = taskPaymentMetaData(context, issue); - if (!issueDetailed.priceLabel || !issueDetailed.priorityLabel || !issueDetailed.timelabel) { - logger.info(`Skipping... its not a bounty`); - return ErrorDiff(`No valid bounty label on this issue`); + if (!task.priceLabel || !task.priorityLabel || !task.timeLabel) { + throw logger.fatal("Missing required labels", { issueDetailed: task }); } - // check for label altering here - const labelChanges = await getLabelChanges(repository.full_name, [issueDetailed.priceLabel, issueDetailed.priorityLabel, issueDetailed.timelabel]); + // get current repository node id from payload and pass it to getLabelChanges function to get label changes + const labelChanges = await label.getLabelChanges(repository.node_id); - await _approveLabelChange(labelChanges.id); + if (labelChanges) { + // Approve label changes + labelChanges.forEach(async (labelChange) => { + await label.approveLabelChange(labelChange.id); + return logger.info("Approved label change", { labelChange }); + }); + } - return `Label change has been approved, permit can now be generated`; -}; + return logger.ok("Label change has been approved, permit can now be generated"); +} diff --git a/src/handlers/comment/handlers/comment-handler-main.ts b/src/handlers/comment/handlers/comment-handler-main.ts new file mode 100644 index 000000000..2f7e3dc6f --- /dev/null +++ b/src/handlers/comment/handlers/comment-handler-main.ts @@ -0,0 +1,134 @@ +import { listAvailableCommands } from "./help"; +import { start } from "./start/start"; +// Commented out until Gnosis Safe is integrated (https://github.com/ubiquity/ubiquibot/issues/353) +// import { payout } from "./payout"; +import { ask } from "./ask"; +import { authorizeLabelChanges } from "./authorize"; +import { setLabels } from "./labels"; +import { multiplier } from "./multiplier"; +import { stop } from "./stop"; +import { registerWallet } from "./wallet"; +// import { addPenalty } from "../../../adapters/supabase"; + +import { UserCommands } from "../../../types/handlers"; +import { query } from "./query"; + +export * from "./ask"; +export * from "./authorize"; +export * from "./help"; +export * from "./multiplier"; +export * from "./query"; +export * from "./start/start"; +export * from "./stop"; +export * from "./wallet"; + +// Parses the comment body and figure out the command name a user wants +export function commentParser(body: string): null | string { + const userCommandIds = userCommands(false).map((cmd) => cmd.id); + const regex = new RegExp(`^(${userCommandIds.join("|")})\\b`); // Regex pattern to match any command at the beginning of the body + + const matches = regex.exec(body); + if (matches) { + const command = matches[0] as string; + if (userCommandIds.includes(command)) { + return command; + } + } + + return null; +} + +export function userCommands(walletVerificationEnabled: boolean): UserCommands[] { + const accountForWalletVerification = walletVerificationDetails(walletVerificationEnabled); + return [ + { + id: "/start", + description: "Assign yourself to the issue.", + example: "/start", + handler: start, + }, + { + id: "/stop", + description: "Unassign yourself from the issue.", + example: "/stop", + handler: stop, + }, + { + id: "/help", + description: "List all available commands.", + example: "/help", + handler: listAvailableCommands, + }, + // Commented out until Gnosis Safe is integrated (https://github.com/ubiquity/ubiquibot/issues/353) + /*{ + id: "/payout", + description: "Disable automatic payment for the issue.", + handler: payout, + },*/ + // { + // id: "/autopay", + // description: "Toggle automatic payment for the completion of the current issue.", + // example: "/autopay true", + // handler: autoPay, + // }, + { + id: "/query", + description: "Returns the user's wallet, access, and multiplier information.", + example: "/query @user", + handler: query, + }, + { + id: "/ask", + description: "Ask a context aware question.", + example: "/ask is x or y the best approach?", + handler: ask, + }, + { + id: "/multiplier", + description: "Set the task payout multiplier for a specific contributor, and provide a reason for why.", + example: '/multiplier @user 0.5 "multiplier reason"', + handler: multiplier, + }, + { + id: "/labels", + description: "Set access control, for admins only.", + example: "/labels @user priority time price", // Ensure there are spaces between words + handler: setLabels, + }, + { + id: "/authorize", + description: "Approve a label change, for admins only.", + example: "/authorize", + handler: authorizeLabelChanges, + }, + { + id: "/wallet", + description: accountForWalletVerification.description, + example: accountForWalletVerification.example, + handler: registerWallet, + }, + ]; +} + +function walletVerificationDetails(walletVerificationEnabled: boolean) { + const base = { + description: "Register your wallet address for payments.", + example: "/wallet ubq.eth", + }; + + const withVerification = { + description: + 'Your message to sign is: "UbiquiBot". You can generate a signature hash using https://etherscan.io/verifiedSignatures', + example: + "0xe2a3e34a63f3def2c29605de82225b79e1398190b542be917ef88a8e93ff9dc91bdc3ef9b12ed711550f6d2cbbb50671aa3f14a665b709ec391f3e603d0899a41b", + }; + + if (walletVerificationEnabled) { + return { + description: `${base.description} ${withVerification.description}`, + example: `${base.example} ${withVerification.example}`, + }; + } else { + return base; + } +} diff --git a/src/handlers/comment/handlers/delegate-compute/delegated-compute.ts b/src/handlers/comment/handlers/delegate-compute/delegated-compute.ts new file mode 100644 index 000000000..56a4812ff --- /dev/null +++ b/src/handlers/comment/handlers/delegate-compute/delegated-compute.ts @@ -0,0 +1,88 @@ +import { Context } from "../../../../types/context"; +import { GitHubEvent } from "../../../../types/github-events"; +import { dispatchWorkflow } from "./remote-permissions"; +export interface DelegatedComputeInputs { + eventName: GitHubEvent; + issueOwner: string; + issueRepository: string; + issueNumber: string; + collaborators: string; +} + +export const computeLocation = { + // // TODO: Make this configurable + owner: "ubiquibot", // "ubiquity", + repository: "comment-incentives", + workflowId: "compute.yml", +}; + +export async function delegateCompute(context: Context, inputs: DelegatedComputeInputs) { + // computeLocation.owner = context.payload?.organization?.login || context.payload.repository.owner.login; + // if (!computeLocation.owner) { + // throw context.logger.error("Compute repository owner is not defined"); + // } + const ref = await getDefaultBranch(context, computeLocation.owner, computeLocation.repository); + + // You must authenticate using an access token with the repo scope to use this endpoint. GitHub Apps must have the actions:write permission to use this endpoint. + // For more information, see "Creating a personal access token for the command line." + // https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens + // const response = await context.octokit.actions.createWorkflowDispatch({ + // owner: computeLocation.owner, + // repo: computeLocation.repository, + // workflow_id: computeLocation.workflowId, + // ref, + + // }); + + // const response = await remoteAuthenticatedDispatch(context, ref, inputs); + + // Example usage in your Probot app: + // Trigger the workflow dispatch here + const response = await dispatchWorkflow(context, { + org: computeLocation.owner, + repo: computeLocation.repository, + workflowId: computeLocation.workflowId, + ref, + inputs: inputs as unknown as { [key: string]: string }, + }); + + if (response.status !== 204) { + throw new Error(`Failed to dispatch workflow. Status: ${response.status}`); + } +} + +async function getDefaultBranch(context: Context, owner: string, repository: string) { + const computeRepositoryFull = await context.octokit.repos.get({ + owner: owner, + repo: repository, + }); + return computeRepositoryFull.data.default_branch; +} +// async function remoteAuthenticatedDispatch(context: Context, ref: string, inputs: DelegatedComputeInputs) { +// // Get the installation ID for the other organization +// const { data: installations } = await context.octokit.apps.listInstallations(); +// if (!installations) { +// throw new Error("No installations found"); +// } +// const installationId = installations.find((installation) => installation.account.login === "ubiquibot").id; + +// // Create a new Octokit instance +// const installationOctokit = new Octokit({ +// authStrategy: Octokit.auth.App, +// auth: { +// id: context.octokit.auth, // replace with your GitHub App's ID +// privateKey: YOUR_PRIVATE_KEY, // replace with your GitHub App's private key +// installationId: installationId, +// }, +// }); + +// // Use the new Octokit instance to dispatch the workflow +// const response = await installationOctokit.actions.createWorkflowDispatch({ +// owner: computeLocation.owner, +// repo: computeLocation.repository, +// workflow_id: computeLocation.workflowId, +// ref, +// inputs: inputs as unknown as { [key: string]: string }, +// }); +// return response; +// } diff --git a/src/handlers/comment/handlers/delegate-compute/remote-permissions.ts b/src/handlers/comment/handlers/delegate-compute/remote-permissions.ts new file mode 100644 index 000000000..42b69eefd --- /dev/null +++ b/src/handlers/comment/handlers/delegate-compute/remote-permissions.ts @@ -0,0 +1,46 @@ +import { Octokit } from "@octokit/rest"; +import { Context } from "../../../../types/context"; + +interface WorkflowDispatchOptions { + org: string; + repo: string; + workflowId: string; + ref: string; + inputs?: { [key: string]: string }; +} + +async function getInstallationOctokitForOrg(context: Context, org: string) { + // You might need to adapt this part based on the actual event type your app handles + const installations = await context.octokit.apps.listInstallations(); + // context.logger.debug("installations", installations); + const installation = installations.data.find((inst) => inst.account?.login === org); + // context.logger.debug("installation", installation); + + if (!installation) { + throw new Error(`No installation found for organization: ${org}`); + } + + return context.octokit.auth({ + type: "installation", + installationId: installation.id, + }) as Promise>; +} + +export async function dispatchWorkflow(context: Context, options: WorkflowDispatchOptions) { + const installationOctokit = (await getInstallationOctokitForOrg(context, options.org)) as InstanceType< + typeof Octokit + > & { token: string }; + + context.logger.debug("installationOctokit", installationOctokit); + const authenticatedOctokit = new Octokit({ auth: installationOctokit.token }); + + console.trace(options.inputs); + + return await authenticatedOctokit.actions.createWorkflowDispatch({ + owner: options.org, + repo: options.repo, + workflow_id: options.workflowId, + ref: options.ref, + inputs: options.inputs, + }); +} diff --git a/src/handlers/comment/handlers/first.ts b/src/handlers/comment/handlers/first.ts index 77e898420..d013be487 100644 --- a/src/handlers/comment/handlers/first.ts +++ b/src/handlers/comment/handlers/first.ts @@ -1,51 +1,39 @@ -import { getBotConfig, getBotContext, getLogger } from "../../../bindings"; -import { upsertCommentToIssue } from "../../../helpers"; -import { Payload } from "../../../types"; +import { Context } from "../../../types/context"; +import { GitHubPayload } from "../../../types/payload"; import { generateHelpMenu } from "./help"; -export const verifyFirstCheck = async (): Promise => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; - let msg = ""; - if (!payload.issue) return; +export async function verifyFirstCommentInRepository(context: Context) { + const payload = context.event.payload as GitHubPayload; + if (!payload.issue) { + throw context.logger.error("Issue is null. Skipping", { issue: payload.issue }, true); + } const { - newContributorGreeting: { header, helpMenu, footer, enabled }, - } = getBotConfig(); - try { - const response_issue = await context.octokit.rest.search.issuesAndPullRequests({ - q: `is:issue repo:${payload.repository.owner.login}/${payload.repository.name} commenter:${payload.sender.login}`, - per_page: 2, - }); - const response_pr = await context.octokit.rest.search.issuesAndPullRequests({ - q: `is:pull-request repo:${payload.repository.owner.login}/${payload.repository.name} commenter:${payload.sender.login}`, - per_page: 2, + features: { + newContributorGreeting: { header, footer, enabled: isEnabled }, + }, + } = context.config; + const responseIssue = await context.event.octokit.rest.search.issuesAndPullRequests({ + q: `is:issue repo:${payload.repository.owner.login}/${payload.repository.name} commenter:${payload.sender.login}`, + per_page: 2, + }); + const responsePr = await context.event.octokit.rest.search.issuesAndPullRequests({ + q: `is:pull-request repo:${payload.repository.owner.login}/${payload.repository.name} commenter:${payload.sender.login}`, + per_page: 2, + }); + if (responseIssue.data.total_count + responsePr.data.total_count === 1) { + //continue_first_search + const data = responseIssue.data.total_count > 0 ? responseIssue.data : responsePr.data; + const resp = await context.event.octokit.rest.issues.listComments({ + issue_number: data.items[0].number, + owner: payload.repository.owner.login, + repo: payload.repository.name, + per_page: 100, }); - if (response_issue.data.total_count + response_pr.data.total_count === 1) { - //continue_first_search - const data = response_issue.data.total_count > 0 ? response_issue.data : response_pr.data; - const resp = await context.octokit.rest.issues.listComments({ - issue_number: data.items[0].number, - owner: payload.repository.owner.login, - repo: payload.repository.name, - per_page: 100, - }); - const isFirstComment = resp.data.filter((item) => item.user?.login === payload.sender.login).length === 1; - if (isFirstComment && enabled) { - //first_comment - if (header) { - msg += `${header}\n`; - } - if (helpMenu) { - msg += `${generateHelpMenu()}\n@${payload.sender.login}\n`; - } - if (footer) { - msg += `${footer}`; - } - await upsertCommentToIssue(payload.issue.number, msg, payload.action, payload.comment); - } + const isFirstComment = resp.data.filter((item) => item.user?.login === payload.sender.login).length === 1; + if (isFirstComment && isEnabled) { + return [header, generateHelpMenu(context), `@${payload.sender.login}`, footer].join("\n"); + // await upsertCommentToIssue(payload.issue.number, msg, payload.action, payload.comment); } - } catch (error: unknown) { - logger.info(`First comment verification failed, reason: ${error}`); } -}; + return context.logger.info(`Skipping first comment`); +} diff --git a/src/handlers/comment/handlers/help.ts b/src/handlers/comment/handlers/help.ts index c2f545049..64ca7e29b 100644 --- a/src/handlers/comment/handlers/help.ts +++ b/src/handlers/comment/handlers/help.ts @@ -1,49 +1,61 @@ -import { userCommands } from "."; -import { getBotConfig, getBotContext, getLogger } from "../../../bindings"; -import { IssueType, Payload } from "../../../types"; -import { IssueCommentCommands } from "../commands"; - -export const listAvailableCommands = async (body: string) => { - const { payload: _payload } = getBotContext(); - const logger = getLogger(); - if (body != IssueCommentCommands.HELP && body.replace(/`/g, "") != IssueCommentCommands.HELP) { - logger.info(`Skipping to list available commands. body: ${body}`); - return; +import { Context } from "../../../types/context"; +import { userCommands } from "./comment-handler-main"; + +export async function listAvailableCommands(context: Context, body: string) { + const logger = context.logger; + if (body != "/help") { + return logger.info("Skipping to list available commands.", { body }); } - const payload = _payload as Payload; - const issue = payload.issue; + const issue = context.payload.issue; if (!issue) { - logger.info("Skipping /help, reason: not issue"); - return; + return context.logger.info("Skipping /help, reason: not issue"); } - if (issue.state == IssueType.CLOSED) { - logger.info("Skipping '/start', reason: closed "); - return; - } + return generateHelpMenu(context); +} + +export function generateHelpMenu(context: Context) { + const config = context.config; + const disabledCommands = config.disabledCommands; + const isStartDisabled = config.disabledCommands.some((command) => command === "start"); + let helpMenu = "### Available Commands\n\n| Command | Description | Example |\n| --- | --- | --- |\n"; + const commands = userCommands(config.miscellaneous.registerWalletWithVerification); - return generateHelpMenu(); -}; - -export const generateHelpMenu = () => { - const config = getBotConfig(); - const startEnabled = config.command.find((command) => command.name === "start"); - let helpMenu = "### Available commands\n```"; - const commands = userCommands(); - commands.map((command) => { - // if first command, add a new line - if (command.id === commands[0].id) { - helpMenu += `\n`; - if (!startEnabled) return; - } - helpMenu += `- ${command.id}: ${command.description}`; - // if not last command, add a new line (fixes too much space below) - if (command.id !== commands[commands.length - 1].id) { - helpMenu += `\n`; - } - }); - - if (!startEnabled) helpMenu += "```\n***_To assign yourself to an issue, please open a draft pull request that is linked to it._***"; + commands + .filter((command) => !disabledCommands.includes(command.id)) + .map( + (command) => + (helpMenu += `| \`${command.id}\` | ${breakSentences(command.description) || ""} | ${ + (command.example && breakLongString(command.example)) || "" + } |\n`) // add to help menu + ); + + if (isStartDisabled) { + helpMenu += "\n\n**To assign yourself to an issue, please open a draft pull request that is linked to it.**"; + } return helpMenu; -}; +} + +function breakLongString(str: string, maxLen = 24) { + const newStr = [] as string[]; + let spaceIndex = str.indexOf(" ", maxLen); // Find the first space after maxLen + + while (str.length > maxLen && spaceIndex !== -1) { + newStr.push(str.slice(0, spaceIndex)); + str = str.slice(spaceIndex + 1); + spaceIndex = str.indexOf(" ", maxLen); + } + + newStr.push(str); // Push the remaining part of the string + + return newStr.join("
      "); +} + +function breakSentences(str: string) { + const sentences = str.endsWith(".") ? str.slice(0, -1).split(". ") : str.split(". "); + if (sentences.length <= 1) { + return str; + } + return sentences.join(".

      "); +} diff --git a/src/handlers/comment/handlers/index.ts b/src/handlers/comment/handlers/index.ts deleted file mode 100644 index 4dcbf7f21..000000000 --- a/src/handlers/comment/handlers/index.ts +++ /dev/null @@ -1,325 +0,0 @@ -import { Comment, Payload, UserCommands } from "../../../types"; -import { IssueCommentCommands } from "../commands"; -import { assign } from "./assign"; -import { listAvailableCommands } from "./help"; -// Commented out until Gnosis Safe is integrated (https://github.com/ubiquity/ubiquibot/issues/353) -// import { payout } from "./payout"; -import { unassign } from "./unassign"; -import { registerWallet } from "./wallet"; -import { approveLabelChange } from "./authorize"; -import { setAccess } from "./allow"; -import { ask } from "./ask"; -import { multiplier } from "./multiplier"; -import { BigNumber, ethers } from "ethers"; -import { addPenalty } from "../../../adapters/supabase"; -import { - addCommentToIssue, - createLabel, - addLabelToIssue, - getLabel, - upsertCommentToIssue, - getAllIssueComments, - getPayoutConfigByNetworkId, - getTokenSymbol, - getAllIssueAssignEvents, - calculateWeight, -} from "../../../helpers"; -import { getBotConfig, getBotContext, getLogger } from "../../../bindings"; -import { - handleIssueClosed, - incentivesCalculation, - calculateIssueConversationReward, - calculateIssueCreatorReward, - calculateIssueAssigneeReward, - calculatePullRequestReviewsReward, -} from "../../payout"; -import { query } from "./query"; -import { autoPay } from "./payout"; -import { getTargetPriceLabel } from "../../shared"; -import Decimal from "decimal.js"; -import { ErrorDiff } from "../../../utils/helpers"; - -export * from "./assign"; -export * from "./wallet"; -export * from "./unassign"; -export * from "./payout"; -export * from "./help"; -export * from "./multiplier"; -export * from "./query"; -export * from "./ask"; -export * from "./authorize"; - -export interface RewardsResponse { - error: string | null; - title?: string; - userId?: number; - username?: string; - reward?: { - account: string; - priceInEth: Decimal; - penaltyAmount: BigNumber; - user: string; - userId: number; - debug: Record; - }[]; - fallbackReward?: Record; -} - -/** - * Parses the comment body and figure out the command name a user wants - * - * - * @param body - The comment body - * @returns The list of command names the comment includes - */ - -export const commentParser = (body: string): IssueCommentCommands[] => { - const regex = /^\/(\w+)\b/; // Regex pattern to match the command at the beginning of the body - - const matches = regex.exec(body); - if (matches) { - const command = matches[0] as IssueCommentCommands; - if (Object.values(IssueCommentCommands).includes(command)) { - return [command]; - } - } - - return []; -}; - -/** - * Callback for issues closed - Processor - */ - -export const issueClosedCallback = async (): Promise => { - const { payload: _payload } = getBotContext(); - const issue = (_payload as Payload).issue; - if (!issue) return; - try { - // assign function incentivesCalculation to a variable - const calculateIncentives = await incentivesCalculation(); - - const creatorReward = await calculateIssueCreatorReward(calculateIncentives); - const assigneeReward = await calculateIssueAssigneeReward(calculateIncentives); - const conversationRewards = await calculateIssueConversationReward(calculateIncentives); - const pullRequestReviewersReward = await calculatePullRequestReviewsReward(calculateIncentives); - - const { error } = await handleIssueClosed(creatorReward, assigneeReward, conversationRewards, pullRequestReviewersReward, calculateIncentives); - - if (error) { - throw new Error(error); - } - } catch (err: unknown) { - return await addCommentToIssue(ErrorDiff(err), issue.number); - } -}; - -/** - * Callback for issues created - Processor - */ - -export const issueCreatedCallback = async (): Promise => { - const logger = getLogger(); - const { payload: _payload } = getBotContext(); - const config = getBotConfig(); - const issue = (_payload as Payload).issue; - if (!issue) return; - const labels = issue.labels; - - const { assistivePricing } = config.mode; - - if (!assistivePricing) { - logger.info("Skipping adding label to issue because assistive pricing is disabled."); - return; - } - - try { - const timeLabels = config.price.timeLabels.filter((item) => labels.map((i) => i.name).includes(item.name)); - const priorityLabels = config.price.priorityLabels.filter((item) => labels.map((i) => i.name).includes(item.name)); - - const minTimeLabel = - timeLabels.length > 0 ? timeLabels.reduce((a, b) => (calculateWeight(a) < calculateWeight(b) ? a : b)).name : config.price.defaultLabels[0]; - const minPriorityLabel = - priorityLabels.length > 0 ? priorityLabels.reduce((a, b) => (calculateWeight(a) < calculateWeight(b) ? a : b)).name : config.price.defaultLabels[1]; - if (!timeLabels.length) await addLabelToIssue(minTimeLabel); - if (!priorityLabels.length) await addLabelToIssue(minPriorityLabel); - - const targetPriceLabel = getTargetPriceLabel(minTimeLabel, minPriorityLabel); - if (targetPriceLabel && !labels.map((i) => i.name).includes(targetPriceLabel)) { - const exist = await getLabel(targetPriceLabel); - if (!exist) await createLabel(targetPriceLabel, "price"); - await addLabelToIssue(targetPriceLabel); - } - } catch (err: unknown) { - await addCommentToIssue(ErrorDiff(err), issue.number); - } -}; - -/** - * Callback for issues reopened - Processor - */ - -export const issueReopenedCallback = async (): Promise => { - const { payload: _payload } = getBotContext(); - const { - payout: { permitBaseUrl }, - } = getBotConfig(); - const logger = getLogger(); - const issue = (_payload as Payload).issue; - const repository = (_payload as Payload).repository; - if (!issue) return; - try { - // find permit comment from the bot - const comments = await getAllIssueComments(issue.number); - const claimUrlRegex = new RegExp(`\\((${permitBaseUrl}\\?claim=\\S+)\\)`); - const permitCommentIdx = comments.findIndex((e) => e.user.type === "Bot" && e.body.match(claimUrlRegex)); - if (permitCommentIdx === -1) { - return; - } - - // extract permit amount and token - const permitComment = comments[permitCommentIdx]; - const permitUrl = permitComment.body.match(claimUrlRegex); - if (!permitUrl || permitUrl.length < 2) { - logger.error(`Permit URL not found`); - return; - } - const url = new URL(permitUrl[1]); - const claimBase64 = url.searchParams.get("claim"); - if (!claimBase64) { - logger.error(`Permit claim search parameter not found`); - return; - } - let networkId = url.searchParams.get("network"); - if (!networkId) { - networkId = "1"; - } - const { rpc } = getPayoutConfigByNetworkId(Number(networkId)); - let claim; - try { - claim = JSON.parse(Buffer.from(claimBase64, "base64").toString("utf-8")); - } catch (err: unknown) { - logger.error(`Error parsing claim: ${err}`); - return; - } - const amount = BigNumber.from(claim.permit.permitted.amount); - const formattedAmount = ethers.utils.formatUnits(amount, 18); - const tokenAddress = claim.permit.permitted.token; - const tokenSymbol = await getTokenSymbol(tokenAddress, rpc); - - // find latest assignment before the permit comment - const events = await getAllIssueAssignEvents(issue.number); - if (events.length === 0) { - logger.error(`No assignment found`); - return; - } - const assignee = events[0].assignee.login; - - if (parseFloat(formattedAmount) > 0) { - // write penalty to db - try { - await addPenalty(assignee, repository.full_name, tokenAddress, networkId.toString(), amount); - } catch (err) { - logger.error(`Error writing penalty to db: ${err}`); - return; - } - - await addCommentToIssue( - `@${assignee} please be sure to review this conversation and implement any necessary fixes. Unless this is closed as completed, its payment of **${formattedAmount} ${tokenSymbol}** will be deducted from your next bounty.`, - issue.number - ); - } else { - logger.info(`Skipped penalty because amount is 0`); - } - } catch (err: unknown) { - await addCommentToIssue(ErrorDiff(err), issue.number); - } -}; - -/** - * Default callback for slash commands - * - * - * @param issue_number - The issue number - * @param comment - Comment string - */ - -const commandCallback = async (issue_number: number, comment: string, action: string, reply_to?: Comment) => { - await upsertCommentToIssue(issue_number, comment, action, reply_to); -}; - -export const userCommands = (): UserCommands[] => { - const config = getBotConfig(); - - return [ - { - id: IssueCommentCommands.START, - description: "Assign the origin sender to the issue automatically.", - handler: assign, - callback: commandCallback, - }, - { - id: IssueCommentCommands.STOP, - description: "Unassign the origin sender from the issue automatically.", - handler: unassign, - callback: commandCallback, - }, - { - handler: listAvailableCommands, - id: IssueCommentCommands.HELP, - description: "List all available commands.", - callback: commandCallback, - }, - // Commented out until Gnosis Safe is integrated (https://github.com/ubiquity/ubiquibot/issues/353) - /*{ - id: IssueCommentCommands.PAYOUT, - description: "Disable automatic payment for the issue.", - handler: payout, - callback: commandCallback, - },*/ - { - id: IssueCommentCommands.AUTOPAY, - description: "Toggle automatic payment for the completion of the current issue.", - handler: autoPay, - callback: commandCallback, - }, - { - id: IssueCommentCommands.QUERY, - description: `Comments the users multiplier and address`, - handler: query, - callback: commandCallback, - }, - { - id: IssueCommentCommands.ASK, - description: `Ask a technical question to the Ubiquity AI. \n example usage: "/ask How do I do X?"`, - handler: ask, - callback: commandCallback, - }, - { - id: IssueCommentCommands.MULTIPLIER, - description: `Set the bounty payout multiplier for a specific contributor, and provide the reason for why. \n example usage: "/wallet @user 0.5 'Multiplier reason'"`, - handler: multiplier, - callback: commandCallback, - }, - { - id: IssueCommentCommands.ALLOW, - description: `Set access control. (Admin Only)`, - handler: setAccess, - callback: commandCallback, - }, - { - id: IssueCommentCommands.AUTHORIZE, - description: `Approve a label change. Superuser only.`, - handler: approveLabelChange, - callback: commandCallback, - }, - { - id: IssueCommentCommands.WALLET, - description: config.wallet.registerWalletWithVerification - ? ` : Register the hunter's wallet address. \n Your message to sign is: DevPool\n You can generate SIGNATURE_HASH at https://etherscan.io/verifiedSignatures\n ex1: /wallet 0x0000000000000000000000000000000000000000 0xe2a3e34a63f3def2c29605de82225b79e1398190b542be917ef88a8e93ff9dc91bdc3ef9b12ed711550f6d2cbbb50671aa3f14a665b709ec391f3e603d0899a41b\n ex2: /wallet vitalik.eth 0x75329f883590507e581cd6dfca62680b6cd12e1f1665db8097f9e642ed70025146b5cf9f777dde90c4a9cbd41500a6bf76bc394fd0b0cae2aab09f7a6f30e3b31b\n` - : `: Register the hunter's wallet address. \n ex1: /wallet 0x0000000000000000000000000000000000000000\n ex2: /wallet vitalik.eth\n`, - handler: registerWallet, - callback: commandCallback, - }, - ]; -}; diff --git a/src/handlers/comment/handlers/issue-closed.ts b/src/handlers/comment/handlers/issue-closed.ts new file mode 100644 index 000000000..b6dbfafbb --- /dev/null +++ b/src/handlers/comment/handlers/issue-closed.ts @@ -0,0 +1,134 @@ +import Runtime from "../../../bindings/bot-runtime"; +import { getAllIssueComments, isUserAdminOrBillingManager } from "../../../helpers/issue"; +import { Context } from "../../../types/context"; +import { GitHubEvent } from "../../../types/github-events"; +import { GitHubComment, GitHubIssue, GitHubPayload, StateReason } from "../../../types/payload"; +import structuredMetadata from "../../shared/structured-metadata"; +import { delegateCompute } from "./delegate-compute/delegated-compute"; +import { getCollaboratorsForRepo } from "./issue/get-collaborator-ids-for-repo"; +// import { getCollaboratorsForRepo } from "./issue/get-collaborator-ids-for-repo"; +// import { getPullRequestComments } from "./issue/get-pull-request-comments"; + +export async function issueClosed(context: Context) { + const payload = context.event.payload as GitHubPayload; + const issue = payload.issue as GitHubIssue; + + const { issueComments, issueOwner, issueRepository, issueNumber } = await getEssentials(context); + await preflightChecks({ issue, issueComments, context }); + + // === Calculate Permit === // + + // const pullRequestComments = await getPullRequestComments(context, owner, repository, issueNumber); + + const collaborators = await getCollaboratorsForRepo(context); + + const installationId = (context.payload.installation as { id: number }).id.toString(); // probot always includes this on issue related events. + + const computeParams = { + eventName: GitHubEvent.ISSUES_CLOSED, + issueOwner, + issueRepository, + issueNumber: `${issueNumber}`, + collaborators: JSON.stringify(collaborators.map((collaborator) => collaborator.login)), // need to serialize to be accepted by workflow + installationId: installationId, + }; + await delegateCompute(context, computeParams); + return Runtime.getState().logger.ok("Evaluating results. Please wait...", computeParams); +} + +async function getEssentials(context: Context) { + const payload = context.event.payload as GitHubPayload; + const issue = payload.issue as GitHubIssue; + const runtime = Runtime.getState(); + const logger = runtime.logger; + if (!issue) throw context.logger.error("Issue is not defined"); + const issueComments = await getAllIssueComments(context, issue.number); + const issueOwner = payload?.organization?.login || payload.repository.owner.login; + if (!issueOwner) throw context.logger.error("Owner is not defined"); + const issueRepository = payload?.repository?.name; + const issueNumber = issue.number; + return { issue, runtime, logger, issueComments, issueOwner, issueRepository, issueNumber }; +} + +interface PreflightChecksParams { + issue: GitHubIssue; + issueComments: GitHubComment[]; + context: Context; +} + +async function preflightChecks({ issue, issueComments, context }: PreflightChecksParams) { + const { payload, config } = context; + if (!issue) throw context.logger.error("Permit generation skipped because issue is undefined"); + if (issue.state_reason !== StateReason.COMPLETED) + throw context.logger.info("Issue was not closed as completed. Skipping.", { issue }); + if (config.features.publicAccessControl.fundExternalClosedIssue) { + const hasPermission = await checkUserPermissionForRepoAndOrg(context, payload.sender.login); + if (!hasPermission) + throw context.logger.error( + "Permit generation disabled because this issue has been closed by an external contributor." + ); + } + + const priceLabels = issue.labels.find((label) => label.name.startsWith("Price: ")); + if (!priceLabels) { + throw context.logger.error("No price label has been set. Skipping permit generation.", { + labels: issue.labels, + }); + } + + const botComments = issueComments.filter((comment: GitHubComment) => comment.user.type === "Bot" /* No Humans */); + checkIfPermitsAlreadyPosted(context, botComments); +} + +function checkIfPermitsAlreadyPosted(context: Context, botComments: GitHubComment[]) { + botComments.forEach((comment) => { + const botComment = structuredMetadata.parse(comment.body); + // if (botComment) { + // console.trace({ parsed: botComment }); + if (botComment?.className === "Permits") { + // in the comment metadata we store what function rendered the comment + console.trace({ parsed: botComment }); + throw context.logger.error("Permit already posted"); + } + // } + }); +} +async function checkUserPermissionForRepoAndOrg(context: Context, username: string): Promise { + const hasPermissionForRepo = await checkUserPermissionForRepo(context, username); + const hasPermissionForOrg = await checkUserPermissionForOrg(context, username); + const userPermission = await isUserAdminOrBillingManager(context, username); + + return hasPermissionForOrg || hasPermissionForRepo || userPermission === "admin"; +} +async function checkUserPermissionForRepo(context: Context, username: string): Promise { + const payload = context.payload; + try { + const res = await context.octokit.rest.repos.checkCollaborator({ + owner: payload.repository.owner.login, + repo: payload.repository.name, + username, + }); + + return res.status === 204; + } catch (e: unknown) { + context.logger.fatal("Checking if user permisson for repo failed!", e); + return false; + } +} + +async function checkUserPermissionForOrg(context: Context, username: string): Promise { + const payload = context.payload; + if (!payload.organization) return false; + + try { + await context.event.octokit.rest.orgs.checkMembershipForUser({ + org: payload.organization.login, + username, + }); + // skipping status check due to type error of checkMembershipForUser function of octokit + return true; + } catch (e: unknown) { + context.logger.fatal("Checking if user permisson for org failed!", e); + return false; + } +} diff --git a/src/handlers/comment/handlers/issue/get-collaborator-ids-for-repo.ts b/src/handlers/comment/handlers/issue/get-collaborator-ids-for-repo.ts new file mode 100644 index 000000000..f9d1c3926 --- /dev/null +++ b/src/handlers/comment/handlers/issue/get-collaborator-ids-for-repo.ts @@ -0,0 +1,18 @@ +import { Context } from "../../../../types/context"; +import { GitHubUser } from "../../../../types/payload"; + +export async function getCollaboratorsForRepo(context: Context): Promise { + const payload = context.payload; + + try { + const collaboratorUsers = (await context.octokit.paginate(context.octokit.rest.repos.listCollaborators, { + owner: payload.repository.owner.login, + repo: payload.repository.name, + per_page: 100, + })) as GitHubUser[]; + return collaboratorUsers; + } catch (err: unknown) { + context.logger.error("Failed to fetch lists of collaborators", err); + return []; + } +} diff --git a/src/handlers/comment/handlers/issue/get-pull-request-comments.ts b/src/handlers/comment/handlers/issue/get-pull-request-comments.ts new file mode 100644 index 000000000..c2722a972 --- /dev/null +++ b/src/handlers/comment/handlers/issue/get-pull-request-comments.ts @@ -0,0 +1,18 @@ +import { getLinkedPullRequests } from "../../../../helpers/get-linked-pull-requests"; +import { getAllIssueComments } from "../../../../helpers/issue"; +import { Context } from "../../../../types/context"; + +import { GitHubComment } from "../../../../types/payload"; + +export async function getPullRequestComments(context: Context, owner: string, repository: string, issueNumber: number) { + const pullRequestComments: GitHubComment[] = []; + const linkedPullRequests = await getLinkedPullRequests(context, { owner, repository, issue: issueNumber }); + if (linkedPullRequests.length) { + const linkedCommentsPromises = linkedPullRequests.map((pull) => getAllIssueComments(context, pull.number)); + const linkedCommentsResolved = await Promise.all(linkedCommentsPromises); + for (const linkedComments of linkedCommentsResolved) { + pullRequestComments.push(...linkedComments); + } + } + return pullRequestComments; +} diff --git a/src/handlers/comment/handlers/labels.ts b/src/handlers/comment/handlers/labels.ts new file mode 100644 index 000000000..3252363be --- /dev/null +++ b/src/handlers/comment/handlers/labels.ts @@ -0,0 +1,58 @@ +import Runtime from "../../../bindings/bot-runtime"; +import { isUserAdminOrBillingManager } from "../../../helpers/issue"; +import { Context } from "../../../types/context"; +import { GitHubPayload } from "../../../types/payload"; + +export async function setLabels(context: Context, body: string) { + const logger = context.logger; + const payload = context.event.payload as GitHubPayload; + const sender = payload.sender.login; + + const sufficientPrivileges = await isUserAdminOrBillingManager(context, sender); + if (!sufficientPrivileges) + return logger.info(`You are not an admin and do not have the required permissions to access this function.`); // if sender is not admin, return + + if (!payload.issue) return context.logger.info(`Skipping '/labels' because of no issue instance`); + + if (body.startsWith("/labels")) { + const { username, labels } = parseComment(body); + const { access, user } = Runtime.getState().adapters.supabase; + const url = payload.comment?.html_url as string; + if (!url) throw new Error("Comment url is undefined"); + + const nodeInfo = { + node_id: payload.comment?.node_id, + node_type: "IssueComment" as const, + node_url: url, + }; + + const userId = await user.getUserId(context.event, username); + await access.setAccess(labels, nodeInfo, userId); + if (!labels.length) { + return context.logger.ok("Successfully cleared access", { username }); + } + return context.logger.ok("Successfully set access", { username, labels }); + } else { + throw logger.fatal( + `Invalid syntax for allow \n usage: '/labels set-(access type) @user true|false' \n ex-1 /labels set-multiplier @user false` + ); + } +} + +function parseComment(comment: string): { username: string; labels: string[] } { + // Extract the @username using a regular expression + const usernameMatch = comment.match(/@(\w+)/); + if (!usernameMatch) throw new Error("Username not found in comment"); + const username = usernameMatch[1]; + + // Split the comment into words and filter out the command and the username + const labels = comment.split(/\s+/).filter((word) => word !== "/labels" && !word.startsWith("@")); + // if (!labels.length) throw new Error("No labels found in comment"); + + // no labels means clear access + + return { + username: username, + labels: labels, + }; +} diff --git a/src/handlers/comment/handlers/multiplier.ts b/src/handlers/comment/handlers/multiplier.ts index a7cc674eb..c9b04ab6f 100644 --- a/src/handlers/comment/handlers/multiplier.ts +++ b/src/handlers/comment/handlers/multiplier.ts @@ -1,51 +1,41 @@ -import { getAccessLevel, upsertWalletMultiplier } from "../../../adapters/supabase"; -import { getBotContext, getLogger } from "../../../bindings"; -import { getUserPermission } from "../../../helpers"; -import { Payload } from "../../../types"; +import Runtime from "../../../bindings/bot-runtime"; +import { isUserAdminOrBillingManager } from "../../../helpers/issue"; +import { Context } from "../../../types/context"; +import { GitHubPayload } from "../../../types/payload"; -export const multiplier = async (body: string) => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; +/** + * You can use this command to set a multiplier for a user. + * It will accept arguments in any order. + * Example usage: + * + * /multiplier @user 0.5 "Multiplier reason" + * /multiplier 0.5 @user "Multiplier reason" + * /multiplier "Multiplier reason" @user 0.5 + * /multiplier 0.5 "Multiplier reason" @user + * /multiplier @user "Multiplier reason" 0.5 + **/ +export async function multiplier(context: Context, body: string) { + const logger = context.logger; + const payload = context.event.payload as GitHubPayload; const sender = payload.sender.login; const repo = payload.repository; - const { repository, organization } = payload; - - const id = organization?.id || repository?.id; // repository?.id as fallback - - logger.info(`Received '/multiplier' command from user: ${sender}`); - + const comment = payload.comment; + if (!comment) return context.logger.info(`Skipping '/multiplier' because of no comment instance`); const issue = payload.issue; - if (!issue) { - logger.info(`Skipping '/multiplier' because of no issue instance`); - return `Skipping '/multiplier' because of no issue instance`; - } - + context.logger.info("Running '/multiplier' command handler", { sender }); + if (!issue) return context.logger.info(`Skipping '/multiplier' because of no issue instance`); const regex = /(".*?"|[^"\s]+)(?=\s*|\s*$)/g; - /** You can use this command to set a multiplier for a user. - * It will accept arguments in any order. - * Example usage: - * - * /multiplier @user 0.5 "Multiplier reason" - * /multiplier 0.5 @user "Multiplier reason" - * /multiplier "Multiplier reason" @user 0.5 - * /multiplier 0.5 "Multiplier reason" @user - * /multiplier @user "Multiplier reason" 0.5 - * - **/ - const matches = body.match(regex); - matches?.shift(); if (matches) { - let bountyMultiplier = 1; - let username = ""; + let taskMultiplier = 1; + let username; let reason = ""; for (const part of matches) { if (!isNaN(parseFloat(part))) { - bountyMultiplier = parseFloat(part); + taskMultiplier = parseFloat(part); } else if (part.startsWith("@")) { username = part.substring(1); } else { @@ -55,33 +45,65 @@ export const multiplier = async (body: string) => { username = username || sender; // check if sender is admin or billing_manager // passing in context so we don't have to make another request to get the user - const permissionLevel = await getUserPermission(sender, context); + const sufficientPrivileges = await isUserAdminOrBillingManager(context, sender); // if sender is not admin or billing_manager, check db for access - if (permissionLevel !== "admin" && permissionLevel !== "billing_manager") { - logger.info(`Getting multiplier access for ${sender} on ${repo.full_name}`); + if (sufficientPrivileges) { + context.logger.info("Getting multiplier access", { + repo: repo.full_name, + user: sender, + }); + // check db permission - const accessible = await getAccessLevel(sender, repo.full_name, "multiplier"); + // await getMultiplier(sender.id, repo.id); + const accessible = await getAccessLevel( + payload.sender.id + // , repo.full_name, "multiplier" + ); if (!accessible) { - logger.info(`User ${sender} is not an admin or billing_manager`); - return "Insufficient permissions to update the payout multiplier. You are not an `admin` or `billing_manager`"; + return logger.error( + "Insufficient permissions to update the payout multiplier. User is not an 'admin' or 'billing_manager'", + { + repo: repo.full_name, + user: sender, + } + ); } } - logger.info(`Upserting to the wallet table, username: ${username}, bountyMultiplier: ${bountyMultiplier}, reason: ${reason}}`); + context.logger.info("Upserting to the wallet table", { username, taskMultiplier, reason }); - await upsertWalletMultiplier(username, bountyMultiplier?.toString(), reason, id?.toString()); - if (bountyMultiplier > 1) { - return `Successfully changed the payout multiplier for @${username} to ${bountyMultiplier}. The reason ${ - reason ? `provided is "${reason}"` : "is not provided" - }. This feature is designed to limit the contributor's compensation for any bounty on the current repository due to other compensation structures (i.e. salary.) are you sure you want to use a bounty multiplier above 1?`; + const { access } = Runtime.getState().adapters.supabase; + await access.upsertMultiplier(payload.sender.id, taskMultiplier, reason, comment); + + if (taskMultiplier > 1) { + return logger.ok( + "Successfully changed the payout multiplier. \ + This feature is designed to limit the contributor's compensation \ + for any task on the current repository \ + due to other compensation structures (i.e. salary.) \ + are you sure you want to use a price multiplier above 1?", + { + username, + taskMultiplier, + reason, + } + ); } else { - return `Successfully changed the payout multiplier for @${username} to ${bountyMultiplier}. The reason ${ - reason ? `provided is "${reason}"` : "is not provided" - }.`; + return context.logger.ok("Successfully changed the payout multiplier", { + username, + taskMultiplier, + reason, + }); } } else { - logger.error("Invalid body for bountyMultiplier command"); - return `Invalid syntax for wallet command \n example usage: "/multiplier @user 0.5 'Multiplier reason'"`; + return logger.fatal( + "Invalid body for taskMultiplier command. Example usage: /multiplier @user 0.5 'Multiplier reason'" + ); } -}; +} + +async function getAccessLevel(userId: number) { + const { access } = Runtime.getState().adapters.supabase; + return await access.getAccess(userId); +} diff --git a/src/handlers/comment/handlers/payout.ts b/src/handlers/comment/handlers/payout.ts deleted file mode 100644 index d5aabc7d6..000000000 --- a/src/handlers/comment/handlers/payout.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { getBotContext, getLogger } from "../../../bindings"; -import { Payload } from "../../../types"; -import { IssueCommentCommands } from "../commands"; -import { - calculateIssueAssigneeReward, - calculateIssueConversationReward, - calculateIssueCreatorReward, - calculatePullRequestReviewsReward, - handleIssueClosed, - incentivesCalculation, -} from "../../payout"; -import { getAllIssueComments, getUserPermission } from "../../../helpers"; -import { GLOBAL_STRINGS } from "../../../configs"; - -export const payout = async (body: string) => { - const { payload: _payload } = getBotContext(); - const logger = getLogger(); - if (body != IssueCommentCommands.PAYOUT && body.replace(/`/g, "") != IssueCommentCommands.PAYOUT) { - logger.info(`Skipping to payout. body: ${body}`); - return; - } - - const payload = _payload as Payload; - logger.info(`Received '/payout' command from user: ${payload.sender.login}`); - const issue = (_payload as Payload).issue; - if (!issue) { - logger.info(`Skipping '/payout' because of no issue instance`); - return; - } - - const _labels = payload.issue?.labels; - if (_labels?.some((e) => e.name.toLowerCase() === "Permitted".toLowerCase())) { - logger.info(`Permit already generated for ${payload.issue?.number}`); - return; - } - - const IssueComments = await getAllIssueComments(issue.number); - if (IssueComments.length === 0) { - return `Permit generation failed due to internal GitHub Error`; - } - - const hasPosted = IssueComments.find((e) => e.user.type === "Bot" && e.body.includes("https://pay.ubq.fi?claim")); - if (hasPosted) { - logger.info(`Permit already generated for ${payload.issue?.number}`); - return; - } - - // assign function incentivesCalculation to a variable - const calculateIncentives = await incentivesCalculation(); - - const creatorReward = await calculateIssueCreatorReward(calculateIncentives); - const assigneeReward = await calculateIssueAssigneeReward(calculateIncentives); - const conversationRewards = await calculateIssueConversationReward(calculateIncentives); - const pullRequestReviewersReward = await calculatePullRequestReviewsReward(calculateIncentives); - - return await handleIssueClosed(creatorReward, assigneeReward, conversationRewards, pullRequestReviewersReward, calculateIncentives); -}; - -export const autoPay = async (body: string) => { - const context = getBotContext(); - const _payload = context.payload; - const logger = getLogger(); - - const payload = _payload as Payload; - logger.info(`Received '/autopay' command from user: ${payload.sender.login}`); - - const pattern = /^\/autopay (true|false)$/; - const res = body.match(pattern); - - if (res) { - const userPermission = await getUserPermission(payload.sender.login, context); - if (userPermission !== "admin" && userPermission !== "billing_manager") { - return "You must be an `admin` or `billing_manager` to toggle automatic payments for completed issues."; - } - if (res.length > 1) { - return `${GLOBAL_STRINGS.autopayComment} **${res[1]}**`; - } - } - return "Invalid body for autopay command: e.g. /autopay false"; -}; diff --git a/src/handlers/comment/handlers/query.ts b/src/handlers/comment/handlers/query.ts index c80f1f15a..feaecab3a 100644 --- a/src/handlers/comment/handlers/query.ts +++ b/src/handlers/comment/handlers/query.ts @@ -1,63 +1,71 @@ -import { getAllAccessLevels, getWalletInfo, upsertAccessControl } from "../../../adapters/supabase"; -import { getBotContext, getLogger } from "../../../bindings"; -import { Payload } from "../../../types"; -import { ErrorDiff } from "../../../utils/helpers"; +import Runtime from "../../../bindings/bot-runtime"; -export const query = async (body: string) => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; - const sender = payload.sender.login; - const { repository, organization } = payload; +import _ from "lodash"; +import { Context } from "../../../types/context"; +import { GitHubPayload } from "../../../types/payload"; - const id = organization?.id || repository?.id; // repository?.id as fallback +export async function query(context: Context, body: string) { + const runtime = Runtime.getState(), + logger = context.logger, + payload = context.event.payload as GitHubPayload, + sender = payload.sender.login; - logger.info(`Received '/query' command from user: ${sender}`); + logger.info("Running '/query' command handler", { sender }); const issue = payload.issue; - if (!issue) { - logger.info(`Skipping '/query' because of no issue instance`); - return `Skipping '/query' because of no issue instance`; - } + if (!issue) return logger.info(`Skipping '/query' because of no issue instance`); const regex = /^\/query\s+@([\w-]+)\s*$/; const matches = body.match(regex); - const user = matches?.[1]; - const repo = payload.repository; - - if (user) { - let data = await getAllAccessLevels(user, repo.full_name); - if (!data) { - logger.info(`Access info does not exist for @${user}`); - try { - await upsertAccessControl(user, repo.full_name, "time_access", true); - data = { - multiplier: false, - priority: false, - time: true, - price: false, - }; - } catch (e) { - ErrorDiff(e); - return `Error upserting access info for @${user}`; + const username = matches?.[1]; + + if (!username) { + throw logger.fatal("Invalid body for query command \n usage /query @user"); + } + + const database = runtime.adapters.supabase; + const usernameResponse = await context.event.octokit.users.getByUsername({ username }); + const user = usernameResponse.data; + if (!user) { + throw logger.fatal("User not found", { username }); + } + const accessData = await database.access.getAccess(user.id); + const walletAddress = await database.wallet.getAddress(user.id); + const messageBuffer = [] as string[]; + + messageBuffer.push(renderMarkdownTableHeader()); + + if (!accessData && !walletAddress) { + return logger.error("No access or wallet found for user", { username }); + } + if (accessData) { + messageBuffer.push(appendToMarkdownTableBody(accessData)); + } + if (walletAddress) { + messageBuffer.push(appendToMarkdownTableBody({ wallet: walletAddress })); + } + + return messageBuffer.join(""); + + function appendToMarkdownTableBody(data: Record, parentKey = ""): string { + const tableStringBuffer = [] as string[]; + + for (const key in data) { + const deCamelKey = _.startCase(_.toLower(key)); + const value = data[key]; + if (typeof value === "object" && value !== null) { + tableStringBuffer.push( + appendToMarkdownTableBody(value as Record, `${parentKey}${deCamelKey} - `) + ); + } else { + tableStringBuffer.push(`| ${parentKey}${deCamelKey} | ${value} |\n`); // Table row } } - const walletInfo = await getWalletInfo(user, id?.toString()); - if (!walletInfo?.address) { - return `Error retrieving multiplier and wallet address for @${user}`; - } else { - return `@${user}'s wallet address is ${walletInfo?.address}, multiplier is ${walletInfo?.multiplier} and access levels are - -| access type | access level | -| ----------- | ------------------- | -| multiplier | ${data.multiplier} | -| priority | ${data.priority} | -| time | ${data.time} | -| price | ${data.price} | - `; - } - } else { - logger.error("Invalid body for query command"); - return `Invalid syntax for query command \n usage /query @user`; + + return tableStringBuffer.join(""); } -}; +} + +function renderMarkdownTableHeader(): string { + return "| Property | Value |\n| --- | --- |\n"; // Table header +} diff --git a/src/handlers/comment/handlers/start/check-task-stale.ts b/src/handlers/comment/handlers/start/check-task-stale.ts new file mode 100644 index 000000000..c148b980c --- /dev/null +++ b/src/handlers/comment/handlers/start/check-task-stale.ts @@ -0,0 +1,14 @@ +import { GitHubIssue } from "../../../../types/payload"; + +export function checkTaskStale(staleTask: number, issue: GitHubIssue) { + let days: number | undefined; + let staleToDays: number | undefined; + let isTaskStale = false; + + if (staleTask !== 0) { + days = Math.floor((new Date().getTime() - new Date(issue.created_at).getTime()) / (1000 * 60 * 60 * 24)); + staleToDays = Math.floor(staleTask / (1000 * 60 * 60 * 24)); + isTaskStale = days >= staleToDays; + } + return isTaskStale; +} diff --git a/src/handlers/comment/handlers/start/generate-assignment-comment.ts b/src/handlers/comment/handlers/start/generate-assignment-comment.ts new file mode 100644 index 000000000..9274723ba --- /dev/null +++ b/src/handlers/comment/handlers/start/generate-assignment-comment.ts @@ -0,0 +1,47 @@ +import Runtime from "../../../../bindings/bot-runtime"; +import { Context } from "../../../../types/context"; +import { GitHubPayload } from "../../../../types/payload"; + +const options: Intl.DateTimeFormatOptions = { + weekday: "short", + month: "short", + day: "numeric", + hour: "numeric", + minute: "numeric", + timeZone: "UTC", + timeZoneName: "short", +}; + +export async function generateAssignmentComment( + context: Context, + payload: GitHubPayload, + duration: number | null = null +) { + const runtime = Runtime.getState(); + const startTime = new Date().getTime(); + let endTime: null | Date = null; + let deadline: null | string = null; + if (duration) { + endTime = new Date(startTime + duration * 1000); + deadline = endTime.toLocaleString("en-US", options); + } + + const issueCreationTime = payload.issue?.created_at; + if (!issueCreationTime) { + throw context.logger.fatal("Issue creation time is not defined"); + } + + return { + daysElapsedSinceTaskCreation: Math.floor((startTime - new Date(issueCreationTime).getTime()) / 1000 / 60 / 60 / 24), + deadline, + registeredWallet: + (await runtime.adapters.supabase.wallet.getAddress(payload.sender.id)) || + "Please set your wallet address to use `/wallet 0x0000...0000`", + tips: `
      Tips:
      +
        +
      • Use /wallet 0x0000...0000 if you want to update your registered payment wallet address.
      • +
      • Be sure to open a draft pull request as soon as possible to communicate updates on your progress.
      • +
      • Be sure to provide timely updates to us when requested, or you will be automatically unassigned from the task.
      • +
          `, + }; +} diff --git a/src/handlers/comment/handlers/start/get-multiplier-info-to-display.ts b/src/handlers/comment/handlers/start/get-multiplier-info-to-display.ts new file mode 100644 index 000000000..11a0d3c38 --- /dev/null +++ b/src/handlers/comment/handlers/start/get-multiplier-info-to-display.ts @@ -0,0 +1,47 @@ +import { Context } from "../../../../types/context"; +import { GitHubIssue } from "../../../../types/payload"; +import { taskPaymentMetaData } from "../../../wildcard/analytics"; +import { getUserMultiplier } from "./get-user-multiplier"; + +export async function getMultiplierInfoToDisplay( + context: Context, + senderId: number, + repoId: number, + issue: GitHubIssue +) { + const userMultiplier = await getUserMultiplier(senderId, repoId); + const value = userMultiplier?.value || null; + const reason = userMultiplier?.reason || null; + + let totalPriceOfTask: string | null = null; + + if (value && value != 1) { + const task = taskPaymentMetaData(context, issue); + + if (task.priceLabel) { + const price = parsePrice(task.priceLabel); + price.number *= value; + totalPriceOfTask = `${price.number} ${price.currency}`; + } else { + totalPriceOfTask = "Permit generation disabled because price label is not set."; + } + } + + return { + multiplierAmount: value, + multiplierReason: reason, + totalPriceOfTask: totalPriceOfTask, + }; +} + +function parsePrice(priceString: string) { + const match = priceString.match(/Price: ([\d.]+) (\w+)/); + if (!match) { + throw new Error("Invalid price string"); + } + + const number = parseFloat(match[1]); + const currency = match[3]; + + return { number, currency }; +} diff --git a/src/handlers/comment/handlers/start/get-time-labels-assigned.ts b/src/handlers/comment/handlers/start/get-time-labels-assigned.ts new file mode 100644 index 000000000..4f65ca58a --- /dev/null +++ b/src/handlers/comment/handlers/start/get-time-labels-assigned.ts @@ -0,0 +1,25 @@ +import { BotConfig } from "../../../../types/configuration-types"; +import { Context } from "../../../../types/context"; +import { Label } from "../../../../types/label"; +import { GitHubPayload } from "../../../../types/payload"; + +export function getTimeLabelsAssigned(context: Context, payload: GitHubPayload, config: BotConfig) { + const logger = context.logger; + const labels = payload.issue?.labels; + if (!labels?.length) { + logger.error("Skipping '/start' since no labels are set to calculate the timeline", { labels }); + return; + } + const timeLabelsDefined = config.labels.time; + const timeLabelsAssigned: Label[] = []; + for (const _label of labels) { + const _labelType = typeof _label; + const _labelName = _labelType === "string" ? _label.toString() : _labelType === "object" ? _label.name : "unknown"; + + const timeLabel = timeLabelsDefined.find((label) => label === _labelName); + if (timeLabel) { + timeLabelsAssigned.push(_label); + } + } + return timeLabelsAssigned; +} diff --git a/src/handlers/comment/handlers/start/get-user-multiplier.ts b/src/handlers/comment/handlers/start/get-user-multiplier.ts new file mode 100644 index 000000000..2dfca3b38 --- /dev/null +++ b/src/handlers/comment/handlers/start/get-user-multiplier.ts @@ -0,0 +1,6 @@ +import Runtime from "../../../../bindings/bot-runtime"; + +export async function getUserMultiplier(userId: number, repoId: number) { + const { user } = Runtime.getState().adapters.supabase; + return await user.getMultiplier(userId, repoId); +} diff --git a/src/handlers/comment/handlers/start/start.ts b/src/handlers/comment/handlers/start/start.ts new file mode 100644 index 000000000..8cc3f0401 --- /dev/null +++ b/src/handlers/comment/handlers/start/start.ts @@ -0,0 +1,202 @@ +import { addAssignees, getAllPullRequests } from "../../../../helpers/issue"; +import { calculateDurations } from "../../../../helpers/shared"; +import { Context } from "../../../../types/context"; +import { GitHubIssue, GitHubPayload, GitHubUser, IssueType } from "../../../../types/payload"; +import { isParentIssue } from "../../../pricing/handle-parent-issue"; + +import structuredMetadata from "../../../shared/structured-metadata"; +import { assignTableComment } from "../table"; +import { checkTaskStale } from "./check-task-stale"; +import { generateAssignmentComment } from "./generate-assignment-comment"; +import { getMultiplierInfoToDisplay } from "./get-multiplier-info-to-display"; +import { getTimeLabelsAssigned } from "./get-time-labels-assigned"; +import Runtime from "../../../../bindings/bot-runtime"; + +export async function start(context: Context, body: string) { + const logger = context.logger; + const config = context.config; + const payload = context.event.payload as GitHubPayload; + const issue = payload.issue; + const { + miscellaneous: { maxConcurrentTasks }, + timers: { taskStaleTimeoutDuration }, + disabledCommands, + } = context.config; + + const isStartDisabled = disabledCommands.some((command: string) => command === "start"); + + logger.info("Received '/start' command", { sender: payload.sender.login, body }); + + if (!issue) { + throw logger.error(`Skipping '/start' because of no issue instance`); + } + + if (isStartDisabled) { + throw logger.error("The `/start` command is disabled for this repository."); + } + + if (issue.body && isParentIssue(issue.body)) { + throw logger.error( + "Please select a child issue from the specification checklist to work on. The '/start' command is disabled on parent issues." + ); + } + + const openedPullRequests = await getAvailableOpenedPullRequests(context, payload.sender.login); + logger.info( + `Opened Pull Requests with approved reviews or with no reviews but over 24 hours have passed: ${JSON.stringify( + openedPullRequests + )}` + ); + + const assignedIssues = await getAssignedIssues(context, payload.sender.login); + logger.info("Max issue allowed is", maxConcurrentTasks); + + // check for max and enforce max + if (assignedIssues.length - openedPullRequests.length >= maxConcurrentTasks) { + throw logger.error("Too many assigned issues, you have reached your max limit", { + maxConcurrentTasks, + }); + } + + if (issue.state == IssueType.CLOSED) { + throw logger.error("Skipping '/start' because the issue is closed."); + } + const assignees: GitHubUser[] = (payload.issue?.assignees ?? []).filter(Boolean) as GitHubUser[]; + + if (assignees.length !== 0) { + throw logger.error("Skipping '/start' because the issue is already assigned."); + } + + // check if wallet is set, if not then throw an error + const sender = payload.sender; + const database = Runtime.getState().adapters.supabase; + const address = database.wallet.getAddress(sender.id); + if (!address) { + throw logger.error("Skipping '/start' because the wallet is not set. Please set your wallet first. /wallet 0x0000"); + } + + // ==== preamble checks completed ==== // + + const labels = issue.labels; + const priceLabel = labels.find((label) => label.name.startsWith("Price: ")); + + let duration: number | null = null; + if (!priceLabel) { + throw logger.error("No price label is set, so this is not ready to be self assigned yet.", priceLabel); + } else { + const timeLabelsAssigned = getTimeLabelsAssigned(context, payload, config); + if (timeLabelsAssigned) { + duration = calculateDurations(timeLabelsAssigned).shift() || null; + } + } + + const comment = await generateAssignmentComment(context, payload, duration); + const metadata = structuredMetadata.create("Assignment", { duration, priceLabel }); + + if (!assignees.map((i) => i.login).includes(payload.sender.login)) { + logger.info("Adding the assignee", { assignee: payload.sender.login }); + await addAssignees(context, issue.number, [payload.sender.login]); + } + + const isTaskStale = checkTaskStale(taskStaleTimeoutDuration, issue); + + // double check whether the assign message has been already posted or not + logger.info("Creating an issue comment", { comment }); + + const { multiplierAmount, multiplierReason, totalPriceOfTask } = await getMultiplierInfoToDisplay( + context, + payload.sender.id, + payload.repository.id, + issue + ); + return [ + assignTableComment({ + multiplierAmount, + multiplierReason, + totalPriceOfTask, + isTaskStale, + daysElapsedSinceTaskCreation: comment.daysElapsedSinceTaskCreation, + taskDeadline: comment.deadline, + registeredWallet: comment.registeredWallet, + }), + comment.tips, + metadata, + ].join("\n"); +} +async function getAvailableOpenedPullRequests(context: Context, username: string) { + const { reviewDelayTolerance } = context.config.timers; + if (!reviewDelayTolerance) return []; + + const openedPullRequests = await getOpenedPullRequests(context, username); + const result = [] as typeof openedPullRequests; + + for (let i = 0; i < openedPullRequests.length; i++) { + const openedPullRequest = openedPullRequests[i]; + const reviews = await getAllPullRequestReviews(context, openedPullRequest.number); + + if (reviews.length > 0) { + const approvedReviews = reviews.find((review) => review.state === "APPROVED"); + if (approvedReviews) { + result.push(openedPullRequest); + } + } + + if ( + reviews.length === 0 && + (new Date().getTime() - new Date(openedPullRequest.created_at).getTime()) / (1000 * 60 * 60) >= + reviewDelayTolerance + ) { + result.push(openedPullRequest); + } + } + return result; +} + +async function getOpenedPullRequests(context: Context, username: string) { + const prs = await getAllPullRequests(context, "open"); + return prs.filter((pr) => !pr.draft && (pr.user?.login === username || !username)); +} +async function getAllPullRequestReviews( + context: Context, + pullNumber: number, + format: "raw" | "html" | "text" | "full" = "raw" +) { + const payload = context.payload; + + try { + const reviews = await context.octokit.paginate(context.octokit.rest.pulls.listReviews, { + owner: payload.repository.owner.login, + repo: payload.repository.name, + pull_number: pullNumber, + per_page: 100, + mediaType: { + format, + }, + }); + return reviews; + } catch (err: unknown) { + context.logger.fatal("Fetching all pull request reviews failed!", err); + return []; + } +} +async function getAssignedIssues(context: Context, username: string): Promise { + const payload = context.payload; + + try { + const issues = (await context.octokit.paginate( + context.octokit.issues.listForRepo, + { + owner: payload.repository.owner.login, + repo: payload.repository.name, + state: IssueType.OPEN, + per_page: 1000, + }, + ({ data: issues }) => + issues.filter((issue) => !issue.pull_request && issue.assignee && issue.assignee.login === username) + )) as GitHubIssue[]; + return issues; + } catch (err: unknown) { + context.logger.fatal("Fetching assigned issues failed!", err); + return []; + } +} diff --git a/src/handlers/comment/handlers/stop.ts b/src/handlers/comment/handlers/stop.ts new file mode 100644 index 000000000..6c347f8e2 --- /dev/null +++ b/src/handlers/comment/handlers/stop.ts @@ -0,0 +1,47 @@ +import { Context } from "../../../types/context"; +import { GitHubPayload } from "../../../types/payload"; +import { closePullRequestForAnIssue } from "../../assign/assign-command-handler"; + +export async function stop(context: Context, body: string) { + const logger = context.logger; + if (!body.startsWith("/stop")) { + return logger.fatal("Skipping to unassign", { body }); + } + + const payload = context.event.payload as GitHubPayload; + logger.info("Running '/stop' command handler", { sender: payload.sender.login }); + const issue = payload.issue; + if (!issue) { + return logger.info(`Skipping '/stop' because of no issue instance`); + } + + const issueNumber = issue.number; + const assignees = payload.issue?.assignees ?? []; + + if (assignees.length == 0) { + return logger.error("No assignees found for issue", { issueNumber }); + } + const shouldUnassign = assignees[0]?.login.toLowerCase() == payload.sender.login.toLowerCase(); + logger.debug("Unassigning sender", { + sender: payload.sender.login.toLowerCase(), + assignee: assignees[0]?.login.toLowerCase(), + shouldUnassign, + }); + + if (shouldUnassign) { + await closePullRequestForAnIssue(context); + const { login } = payload.repository.owner; + const { name: repo } = payload.repository; + await context.event.octokit.rest.issues.removeAssignees({ + owner: login, + repo: repo, + issue_number: issueNumber, + assignees: [payload.sender.login], + }); + return logger.ok("You have been unassigned from the task", { + issueNumber, + user: payload.sender.login, + }); + } + return logger.error("You are not assigned to this task", { issueNumber, user: payload.sender.login }); +} diff --git a/src/handlers/comment/handlers/table.ts b/src/handlers/comment/handlers/table.ts index 97f154e0b..c204c2674 100644 --- a/src/handlers/comment/handlers/table.ts +++ b/src/handlers/comment/handlers/table.ts @@ -1,38 +1,42 @@ -export const tableComment = ({ - deadline, - wallet, - multiplier, - reason, - bounty, - isBountyStale, - days, -}: { - deadline: string; - wallet: string; - multiplier?: string; - reason?: string; - bounty?: string; - isBountyStale?: boolean; - days?: number; -}) => { +export function assignTableComment({ + taskDeadline, + registeredWallet, + multiplierAmount, + multiplierReason, + totalPriceOfTask, + isTaskStale, + daysElapsedSinceTaskCreation, +}: AssignTableCommentParams) { + let taskStaleWarning = ``; + if (isTaskStale) { + taskStaleWarning = `Warning! This task was created over ${daysElapsedSinceTaskCreation} days ago. Please confirm that this issue specification is accurate before starting.`; + } + let deadlineWarning = ``; + if (taskDeadline) { + deadlineWarning = `Deadline${taskDeadline}`; + } + return ` -${ - isBountyStale - ? `` - : `` -} - - - - +${taskStaleWarning} +${deadlineWarning} - + -${multiplier ? `` : ``} -${reason ? `` : ``} -${bounty ? `` : ``} +${multiplierAmount ? `` : ``} +${multiplierReason ? `` : ``} +${totalPriceOfTask ? `` : ``}
          Warning! This task was created over ${days} days ago. Please confirm that this issue specification is accurate before starting.
          Deadline${deadline}
          Registered Wallet${wallet}${registeredWallet}
          Payment Multiplier${multiplier}
          Multiplier Reason${reason}
          Total Bounty${bounty}
          Payment Multiplier${multiplierAmount}
          Multiplier Reason${multiplierReason}
          Total Price${totalPriceOfTask}
          `; -}; +} + +interface AssignTableCommentParams { + taskDeadline: string | null; + registeredWallet: string; + multiplierAmount: number | null; + multiplierReason: string | null; + totalPriceOfTask: string | null; + isTaskStale: boolean; + daysElapsedSinceTaskCreation: number; +} diff --git a/src/handlers/comment/handlers/unassign.ts b/src/handlers/comment/handlers/unassign.ts deleted file mode 100644 index 91aae184e..000000000 --- a/src/handlers/comment/handlers/unassign.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { removeAssignees } from "../../../helpers"; -import { getBotContext, getLogger } from "../../../bindings"; -import { Payload } from "../../../types"; -import { IssueCommentCommands } from "../commands"; -import { closePullRequestForAnIssue } from "../../assign/index"; - -export const unassign = async (body: string) => { - const { payload: _payload } = getBotContext(); - const logger = getLogger(); - if (body != IssueCommentCommands.STOP && body.replace(/`/g, "") != IssueCommentCommands.STOP) { - logger.info(`Skipping to unassign. body: ${body}`); - return; - } - - const payload = _payload as Payload; - logger.info(`Received '/stop' command from user: ${payload.sender.login}`); - const issue = (_payload as Payload).issue; - if (!issue) { - logger.info(`Skipping '/stop' because of no issue instance`); - return; - } - - const issue_number = issue.number; - const _assignees = payload.issue?.assignees; - const assignees = _assignees ?? []; - if (assignees.length == 0) return; - const shouldUnassign = payload.sender.login.toLowerCase() == assignees[0].login.toLowerCase(); - logger.debug(`Unassigning sender: ${payload.sender.login.toLowerCase()}, assignee: ${assignees[0].login.toLowerCase()}, shouldUnassign: ${shouldUnassign}`); - - if (shouldUnassign) { - await closePullRequestForAnIssue(); - await removeAssignees( - issue_number, - assignees.map((i) => i.login) - ); - return `You have been unassigned from the bounty @${payload.sender.login}`; - } - return; -}; diff --git a/src/handlers/comment/handlers/wallet.ts b/src/handlers/comment/handlers/wallet.ts index 6cabfd357..bdd7c2063 100644 --- a/src/handlers/comment/handlers/wallet.ts +++ b/src/handlers/comment/handlers/wallet.ts @@ -1,13 +1,10 @@ -import { ethers } from "ethers"; -import { upsertWalletAddress } from "../../../adapters/supabase"; -import { getBotConfig, getBotContext, getLogger } from "../../../bindings"; -import { resolveAddress } from "../../../helpers"; -import { Payload } from "../../../types"; -import { formatEthAddress } from "../../../utils"; -import { IssueCommentCommands } from "../commands"; -import { constants } from "ethers"; +import { constants, ethers } from "ethers"; +import Runtime from "../../../bindings/bot-runtime"; +import { Context } from "../../../types/context"; +import { GitHubPayload } from "../../../types/payload"; + // Extracts ensname from raw text. -const extractEnsName = (text: string): string | undefined => { +function extractEnsName(text: string) { // Define a regular expression to match ENS names const ensRegex = /^(?=.{3,40}$)([a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z]{2,}$/gm; @@ -18,70 +15,79 @@ const extractEnsName = (text: string): string | undefined => { const ensName = match[0]; return ensName.toLowerCase(); } +} - return undefined; -}; - -export const registerWallet = async (body: string) => { - const { payload: _payload } = getBotContext(); - const config = getBotConfig(); - const logger = getLogger(); - const payload = _payload as Payload; +export async function registerWallet(context: Context, body: string) { + const runtime = Runtime.getState(); + const payload = context.event.payload as GitHubPayload; + const config = context.config; + const logger = context.logger; const sender = payload.sender.login; + const regexForAddress = /(0x[a-fA-F0-9]{40})/g; const addressMatches = body.match(regexForAddress); let address = addressMatches ? addressMatches[0] : null; - const ensName = extractEnsName(body.replace(IssueCommentCommands.WALLET, "").trim()); - logger.info(`Received '/wallet' command from user: ${sender}, body: ${body}, ${ensName}`); - - if (!address && !ensName) { - logger.info("Skipping to register a wallet address because both address/ens doesn't exist"); - if (config.wallet.registerWalletWithVerification) { - return `Please include your wallet or ENS address.\n usage: /wallet 0x0000000000000000000000000000000000000000 0x0830f316c982a7fd4ff050c8fdc1212a8fd92f6bb42b2337b839f2b4e156f05a359ef8f4acd0b57cdedec7874a865ee07076ab2c81dc9f9de28ced55228587f81c`; - } - return `Please include your wallet or ENS address.\n usage: /wallet 0x0000000000000000000000000000000000000000`; - } + const ensName = extractEnsName(body.replace("/wallet", "").trim()); if (!address && ensName) { - logger.info(`Trying to resolve address from Ens name: ${ensName}`); + context.logger.info("Trying to resolve address from ENS name", { ensName }); address = await resolveAddress(ensName); if (!address) { - logger.info(`Resolving address from Ens name failed, EnsName: ${ensName}`); - return `Resolving address from Ens name failed, Try again`; + throw context.logger.fatal("Resolving address from ENS name failed", { ensName }); } - logger.info(`Resolved address from Ens name: ${ensName}, address: ${address}`); + context.logger.ok("Resolved address from ENS name", { ensName, address }); + } + + if (!address) { + return context.logger.info("Skipping to register a wallet address because both address/ens doesn't exist"); } - if (config.wallet.registerWalletWithVerification) { - const regexForSigHash = /(0x[a-fA-F0-9]{130})/g; - const sigHashMatches = body.match(regexForSigHash); - const sigHash = sigHashMatches ? sigHashMatches[0] : null; + if (config.miscellaneous.registerWalletWithVerification) { + registerWalletWithVerification(context, body, address); + } - const messageToSign = "DevPool"; - const failedSigLogMsg = `Skipping to register the wallet address because you have not provided a valid SIGNATURE_HASH.`; - const failedSigResponse = `Skipping to register the wallet address because you have not provided a valid SIGNATURE_HASH. \nUse [etherscan](https://etherscan.io/verifiedSignatures) to sign the message \`${messageToSign}\` and register your wallet by appending the signature hash.\n\n**Usage:**\n/wallet \n\n**Example:**\n/wallet 0x0000000000000000000000000000000000000000 0x0830f316c982a7fd4ff050c8fdc1212a8fd92f6bb42b2337b839f2b4e156f05a359ef8f4acd0b57cdedec7874a865ee07076ab2c81dc9f9de28ced55228587f81c`; - try { - //verifyMessage throws an error when some parts(r,s,v) of the signature are correct but some are not - const isSigHashValid = address && sigHash && ethers.utils.verifyMessage(messageToSign, sigHash) == ethers.utils.getAddress(address); - if (!isSigHashValid) { - logger.info(failedSigLogMsg); - return failedSigResponse; - } - } catch (e) { - logger.info(`Exception thrown by verifyMessage for /wallet: ${e}`); - logger.info(failedSigLogMsg); - return failedSigResponse; - } + if (address == constants.AddressZero) { + return logger.error( + "Skipping to register a wallet address because user is trying to set their address to null address" + ); } - if (address) { - if (address == constants.AddressZero) { - logger.info("Skipping to register a wallet address because user is trying to set their address to null address"); - return `Cannot set address to null address`; + if (payload.comment) { + const { wallet } = runtime.adapters.supabase; + await wallet.upsertWalletAddress(context.event, address); + return context.logger.ok("Successfully registered wallet address", { sender, address }); + } else { + throw new Error("Payload comment is undefined"); + } +} + +function registerWalletWithVerification(context: Context, body: string, address: string) { + const regexForSigHash = /(0x[a-fA-F0-9]{130})/g; + const sigHashMatches = body.match(regexForSigHash); + const sigHash = sigHashMatches ? sigHashMatches[0] : null; + const messageToSign = "UbiquiBot"; + const failedSigLogMsg = `Skipping to register the wallet address because you have not provided a valid SIGNATURE_HASH.`; + + try { + const isSigHashValid = + sigHash && ethers.utils.verifyMessage(messageToSign, sigHash) == ethers.utils.getAddress(address); + if (!isSigHashValid) { + throw context.logger.fatal(failedSigLogMsg); } - await upsertWalletAddress(sender, address); - return `Updated the wallet address for @${sender} successfully!\t Your new address: ${formatEthAddress(address)}`; + } catch (e) { + context.logger.fatal("Exception thrown by verifyMessage for /wallet: ", e); + throw context.logger.fatal(failedSigLogMsg); } +} + +export async function resolveAddress(ensName: string): Promise { + // Gets the Ethereum address associated with an ENS (Ethereum Name Service) name + // Explicitly set provider to Ethereum mainnet + const provider = new ethers.providers.JsonRpcProvider(`https://rpc-bot.ubq.fi/v1/mainnet`); // mainnet required for ENS + const address = await provider.resolveName(ensName).catch((err) => { + console.trace({ err }); + return null; + }); - return; -}; + return address; +} diff --git a/src/handlers/comment/index.ts b/src/handlers/comment/index.ts deleted file mode 100644 index 65dfc5193..000000000 --- a/src/handlers/comment/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./action"; -export * from "./handlers"; diff --git a/src/handlers/index.ts b/src/handlers/index.ts deleted file mode 100644 index 6ccf96f9a..000000000 --- a/src/handlers/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export * from "./processors"; - -// issues handlers -export * from "./pricing"; -export * from "./shared"; -export * from "./assign"; - -// issue_comment handlers -export * from "./comment"; diff --git a/src/handlers/issue/index.ts b/src/handlers/issue/index.ts deleted file mode 100644 index 12e1212ae..000000000 --- a/src/handlers/issue/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./pre"; diff --git a/src/handlers/issue/pre.ts b/src/handlers/issue/pre.ts deleted file mode 100644 index bebda5dce..000000000 --- a/src/handlers/issue/pre.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { extractImportantWords, upsertCommentToIssue, measureSimilarity } from "../../helpers"; -import { getBotContext, getLogger } from "../../bindings"; -import { Issue, Payload } from "../../types"; - -export const findDuplicateOne = async () => { - const logger = getLogger(); - const context = getBotContext(); - const payload = context.payload as Payload; - const issue = payload.issue; - - if (!issue?.body) return; - const importantWords = await extractImportantWords(issue); - const perPage = 10; - let curPage = 1; - - for (const importantWord of importantWords) { - let fetchDone = false; - try { - while (!fetchDone) { - const response = await context.octokit.rest.search.issuesAndPullRequests({ - q: `${importantWord} repo:${payload.repository.owner.login}/${payload.repository.name} is:issue`, - sort: "created", - order: "desc", - per_page: perPage, - page: curPage, - }); - if (response.data.items.length > 0) { - for (const result of response.data.items) { - if (!result.body) continue; - if (result.id === issue.id) continue; - const similarity = await measureSimilarity(issue, result as Issue); - if (similarity > parseInt(process.env.SIMILARITY_THRESHOLD || "80")) { - await upsertCommentToIssue( - issue.number, - `Similar issue (${result.title}) found at ${result.html_url}.\nSimilarity is about ${similarity}%`, - "created" - ); - return; - } - } - } - if (response.data.items.length < perPage) fetchDone = true; - else curPage++; - } - } catch (e: unknown) { - logger.error(`Could not find any issues, reason: ${e}`); - } - } -}; diff --git a/src/handlers/label/index.ts b/src/handlers/label/index.ts deleted file mode 100644 index 491d49f74..000000000 --- a/src/handlers/label/index.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { saveLabelChange } from "../../adapters/supabase"; -import { getBotContext, getLogger } from "../../bindings"; -import { hasLabelEditPermission } from "../../helpers"; -import { Payload } from "../../types"; - -export const watchLabelChange = async () => { - const logger = getLogger(); - const context = getBotContext(); - - const payload = context.payload as Payload; - - const { repository, label, changes, sender } = payload; - - const { full_name } = repository; - - const previousLabel = changes?.name.from; - const currentLabel = label?.name; - const triggerUser = sender.login; - - if (!previousLabel || !currentLabel) { - logger.debug("watchLabelChange: No label name change.. skipping"); - return; - } - - // check if user is authorized to make the change - const hasAccess = await hasLabelEditPermission(currentLabel, triggerUser, repository.full_name); - - await saveLabelChange(triggerUser, full_name, previousLabel, currentLabel, hasAccess); - logger.debug("watchLabelChange: label name change saved to db"); -}; diff --git a/src/handlers/label/label.ts b/src/handlers/label/label.ts new file mode 100644 index 000000000..914e7fe37 --- /dev/null +++ b/src/handlers/label/label.ts @@ -0,0 +1,56 @@ +import Runtime from "../../bindings/bot-runtime"; +import { isUserAdminOrBillingManager } from "../../helpers/issue"; +import { Context } from "../../types/context"; +import { GitHubPayload } from "../../types/payload"; + +export async function watchLabelChange(context: Context) { + const logger = context.logger; + + const payload = context.event.payload as GitHubPayload; + const { label, changes, sender } = payload; + + const previousLabel = changes?.name?.from; + if (!previousLabel) { + throw logger.error("previous label name is undefined"); + } + const currentLabel = label?.name; + const triggerUser = sender.login; + + if (!previousLabel || !currentLabel) { + return logger.debug("No label name change.. skipping"); + } + + // check if user is authorized to make the change + const hasAccess = await hasLabelEditPermission(context, currentLabel, triggerUser); + + const { supabase } = Runtime.getState().adapters; + + await supabase.label.saveLabelChange({ + previousLabel, + currentLabel, + authorized: hasAccess, + repository: payload.repository, + }); + return logger.debug("label name change saved to db"); +} + +async function hasLabelEditPermission(context: Context, label: string, caller: string) { + const logger = context.logger; + const sufficientPrivileges = await isUserAdminOrBillingManager(context, caller); + + // get text before : + const match = label.split(":"); + if (match.length == 0) return false; + + if (sufficientPrivileges) { + // check permission + const { access, user } = Runtime.getState().adapters.supabase; + const userId = await user.getUserId(context.event, caller); + const accessible = await access.getAccess(userId); + if (accessible) return true; + logger.info("No access to edit label", { caller, label }); + return false; + } + + return true; +} diff --git a/src/handlers/payout/action.ts b/src/handlers/payout/action.ts deleted file mode 100644 index 25bf01562..000000000 --- a/src/handlers/payout/action.ts +++ /dev/null @@ -1,521 +0,0 @@ -import { BigNumber, ethers } from "ethers"; -import { getLabelChanges, getPenalty, getWalletAddress, getWalletMultiplier, removePenalty } from "../../adapters/supabase"; -import { getBotConfig, getBotContext, getLogger } from "../../bindings"; -import { - addLabelToIssue, - checkUserPermissionForRepoAndOrg, - clearAllPriceLabelsOnIssue, - deleteLabel, - generatePermit2Signature, - getAllIssueComments, - getTokenSymbol, - wasIssueReopened, - getAllIssueAssignEvents, - addCommentToIssue, - createDetailsTable, - savePermitToDB, -} from "../../helpers"; -import { UserType, Payload, StateReason, Comment, User, Incentives, Issue } from "../../types"; -import { bountyInfo } from "../wildcard"; -import Decimal from "decimal.js"; -import { GLOBAL_STRINGS } from "../../configs"; -import { isParentIssue } from "../pricing"; -import { RewardsResponse } from "../comment"; - -export interface IncentivesCalculationResult { - id: number; - paymentToken: string; - rpc: string; - networkId: number; - privateKey: string; - paymentPermitMaxPrice: number; - baseMultiplier: number; - incentives: Incentives; - issueCreatorMultiplier: number; - recipient: string; - multiplier: number; - issue: Issue; - payload: Payload; - comments: Comment[]; - issueDetailed: { - isBounty: boolean; - timelabel: string; - priorityLabel: string; - priceLabel: string; - }; - assignee: User; - tokenSymbol: string; - claimUrlRegex: RegExp; -} - -export interface RewardByUser { - account: string; - priceInEth: Decimal; - userId: number | undefined; - issueId: string; - type: (string | undefined)[]; - user: string | undefined; - priceArray: string[]; - debug: Record; -} - -/** - * Collect the information required for the permit generation and error handling - */ - -export const incentivesCalculation = async (): Promise => { - const context = getBotContext(); - const { - payout: { paymentToken, rpc, permitBaseUrl, networkId, privateKey }, - mode: { incentiveMode, paymentPermitMaxPrice }, - price: { incentives, issueCreatorMultiplier, baseMultiplier }, - accessControl, - } = getBotConfig(); - const logger = getLogger(); - const payload = context.payload as Payload; - const issue = payload.issue; - const { repository, organization } = payload; - - const id = organization?.id || repository?.id; // repository?.id as fallback - - if (!issue) { - throw new Error("Permit generation skipped because issue is undefined"); - } - - if (accessControl.organization) { - const userHasPermission = await checkUserPermissionForRepoAndOrg(payload.sender.login, context); - - if (!userHasPermission) { - throw new Error("Permit generation disabled because this issue has been closed by an external contributor."); - } - } - - const comments = await getAllIssueComments(issue.number); - - const wasReopened = await wasIssueReopened(issue.number); - const claimUrlRegex = new RegExp(`\\((${permitBaseUrl}\\?claim=\\S+)\\)`); - const permitCommentIdx = comments.findIndex((e) => e.user.type === UserType.Bot && e.body.match(claimUrlRegex)); - - if (wasReopened && permitCommentIdx !== -1) { - const permitComment = comments[permitCommentIdx]; - const permitUrl = permitComment.body.match(claimUrlRegex); - if (!permitUrl || permitUrl.length < 2) { - logger.error(`Permit URL not found`); - throw new Error("Permit generation skipped because permit URL not found"); - } - const url = new URL(permitUrl[1]); - const claimBase64 = url.searchParams.get("claim"); - if (!claimBase64) { - logger.error(`Permit claim search parameter not found`); - throw new Error("Permit generation skipped because permit claim search parameter not found"); - } - let networkId = url.searchParams.get("network"); - if (!networkId) { - networkId = "1"; - } - let claim; - try { - claim = JSON.parse(Buffer.from(claimBase64, "base64").toString("utf-8")); - } catch (err: unknown) { - logger.error(`${err}`); - throw new Error("Permit generation skipped because permit claim is invalid"); - } - const amount = BigNumber.from(claim.permit.permitted.amount); - const tokenAddress = claim.permit.permitted.token; - - // extract assignee - const events = await getAllIssueAssignEvents(issue.number); - if (events.length === 0) { - logger.error(`No assignment found`); - throw new Error("Permit generation skipped because no assignment found"); - } - const assignee = events[0].assignee.login; - - try { - await removePenalty(assignee, payload.repository.full_name, tokenAddress, networkId, amount); - } catch (err) { - logger.error(`Failed to remove penalty: ${err}`); - throw new Error("Permit generation skipped because failed to remove penalty"); - } - - logger.info(`Penalty removed`); - throw new Error("Permit generation skipped, penalty removed"); - } - - if (!incentiveMode) { - logger.info(`No incentive mode. skipping to process`); - throw new Error("No incentive mode. skipping to process"); - } - - if (privateKey == "") { - logger.info("Permit generation disabled because wallet private key is not set."); - throw new Error("Permit generation disabled because wallet private key is not set."); - } - - if (issue.state_reason !== StateReason.COMPLETED) { - logger.info("Permit generation disabled because this is marked as unplanned."); - throw new Error("Permit generation disabled because this is marked as unplanned."); - } - - logger.info(`Checking if the issue is a parent issue.`); - if (issue.body && isParentIssue(issue.body)) { - logger.error("Permit generation disabled because this is a collection of issues."); - await clearAllPriceLabelsOnIssue(); - throw new Error("Permit generation disabled because this is a collection of issues."); - } - - logger.info(`Handling issues.closed event, issue: ${issue.number}`); - for (const botComment of comments.filter((cmt) => cmt.user.type === UserType.Bot).reverse()) { - const botCommentBody = botComment.body; - if (botCommentBody.includes(GLOBAL_STRINGS.autopayComment)) { - const pattern = /\*\*(\w+)\*\*/; - const res = botCommentBody.match(pattern); - if (res) { - if (res[1] === "false") { - logger.info(`Skipping to generate permit2 url, reason: autoPayMode for this issue: false`); - throw new Error(`Permit generation disabled because automatic payment for this issue is disabled.`); - } - break; - } - } - } - - if (paymentPermitMaxPrice == 0 || !paymentPermitMaxPrice) { - logger.info(`Skipping to generate permit2 url, reason: { paymentPermitMaxPrice: ${paymentPermitMaxPrice}}`); - throw new Error(`Permit generation disabled because paymentPermitMaxPrice is 0.`); - } - - const issueDetailed = bountyInfo(issue); - if (!issueDetailed.isBounty) { - logger.info(`Skipping... its not a bounty`); - throw new Error(`Permit generation disabled because this issue didn't qualify as bounty.`); - } - - if (!issueDetailed.priceLabel || !issueDetailed.priorityLabel || !issueDetailed.timelabel) { - logger.info(`Skipping... its not a bounty`); - throw new Error(`Permit generation disabled because this issue didn't qualify as bounty.`); - } - - // check for label altering here - const labelChanges = await getLabelChanges(repository.full_name, [issueDetailed.priceLabel, issueDetailed.priorityLabel, issueDetailed.timelabel]); - - if (labelChanges) { - // if approved is still false, it means user was certainly not authorized for that edit - if (!labelChanges.approved) { - logger.info(`Skipping... label was changed by unauthorized user`); - throw new Error(`Permit generation disabled because label: "${labelChanges.label_to}" was modified by an unauthorized user`); - } - } - - const assignees = issue?.assignees ?? []; - const assignee = assignees.length > 0 ? assignees[0] : undefined; - if (!assignee) { - logger.info("Skipping to proceed the payment because `assignee` is undefined"); - throw new Error(`Permit generation disabled because assignee is undefined.`); - } - - if (!issueDetailed.priceLabel) { - logger.info("Skipping to proceed the payment because price not set"); - throw new Error(`Permit generation disabled because price label is not set.`); - } - - const recipient = await getWalletAddress(assignee.login); - if (!recipient || recipient?.trim() === "") { - logger.info(`Recipient address is missing`); - throw new Error(`Permit generation skipped because recipient address is missing`); - } - - const { value: multiplier } = await getWalletMultiplier(assignee.login, id?.toString()); - - if (multiplier === 0) { - const errMsg = "Refusing to generate the payment permit because " + `@${assignee.login}` + "'s payment `multiplier` is `0`"; - logger.info(errMsg); - throw new Error(errMsg); - } - - const permitComments = comments.filter((content) => content.body.includes("https://pay.ubq.fi?claim=") && content.user.type == UserType.Bot); - - if (permitComments.length > 0) { - logger.info(`skip to generate a permit url because it has been already posted`); - throw new Error(`skip to generate a permit url because it has been already posted`); - } - - const tokenSymbol = await getTokenSymbol(paymentToken, rpc); - - return { - id, - paymentToken, - rpc, - networkId, - privateKey, - recipient, - multiplier, - paymentPermitMaxPrice, - baseMultiplier, - incentives, - issueCreatorMultiplier, - issue, - payload, - comments, - issueDetailed: { - isBounty: issueDetailed.isBounty, - timelabel: issueDetailed.timelabel, - priorityLabel: issueDetailed.priorityLabel, - priceLabel: issueDetailed.priceLabel, - }, - assignee, - tokenSymbol, - claimUrlRegex, - }; -}; - -/** - * Calculate the reward for the assignee - */ - -export const calculateIssueAssigneeReward = async (incentivesCalculation: IncentivesCalculationResult): Promise => { - const logger = getLogger(); - const assigneeLogin = incentivesCalculation.assignee.login; - - let priceInEth = new Decimal(incentivesCalculation.issueDetailed.priceLabel.substring(7, incentivesCalculation.issueDetailed.priceLabel.length - 4)).mul( - incentivesCalculation.multiplier - ); - if (priceInEth.gt(incentivesCalculation.paymentPermitMaxPrice)) { - logger.info("Skipping to proceed the payment because bounty payout is higher than paymentPermitMaxPrice."); - return { error: `Permit generation disabled because issue's bounty is higher than ${incentivesCalculation.paymentPermitMaxPrice}` }; - } - - // if bounty hunter has any penalty then deduct it from the bounty - const penaltyAmount = await getPenalty( - assigneeLogin, - incentivesCalculation.payload.repository.full_name, - incentivesCalculation.paymentToken, - incentivesCalculation.networkId.toString() - ); - if (penaltyAmount.gt(0)) { - logger.info(`Deducting penalty from bounty`); - const bountyAmount = ethers.utils.parseUnits(priceInEth.toString(), 18); - const bountyAmountAfterPenalty = bountyAmount.sub(penaltyAmount); - if (bountyAmountAfterPenalty.lte(0)) { - await removePenalty( - assigneeLogin, - incentivesCalculation.payload.repository.full_name, - incentivesCalculation.paymentToken, - incentivesCalculation.networkId.toString(), - bountyAmount - ); - const msg = `Permit generation disabled because bounty amount after penalty is 0.`; - logger.info(msg); - return { error: msg }; - } - priceInEth = new Decimal(ethers.utils.formatUnits(bountyAmountAfterPenalty, 18)); - } - - const account = await getWalletAddress(assigneeLogin); - - return { - title: "Issue-Assignee", - error: "", - userId: incentivesCalculation.assignee.id, - username: assigneeLogin, - reward: [ - { - priceInEth, - penaltyAmount, - account: account || "0x", - user: "", - userId: incentivesCalculation.assignee.id, - debug: {}, - }, - ], - }; -}; - -export const handleIssueClosed = async ( - creatorReward: RewardsResponse, - assigneeReward: RewardsResponse, - conversationRewards: RewardsResponse, - pullRequestReviewersReward: RewardsResponse, - incentivesCalculation: IncentivesCalculationResult -): Promise<{ error: string }> => { - const logger = getLogger(); - const { comments } = getBotConfig(); - const issueNumber = incentivesCalculation.issue.number; - - let permitComment = ""; - const title = ["Issue-Assignee"]; - - // Rewards by user - const rewardByUser: RewardByUser[] = []; - - // ASSIGNEE REWARD PRICE PROCESSOR - const priceInEth = new Decimal(incentivesCalculation.issueDetailed.priceLabel.substring(7, incentivesCalculation.issueDetailed.priceLabel.length - 4)).mul( - incentivesCalculation.multiplier - ); - - if (priceInEth.gt(incentivesCalculation.paymentPermitMaxPrice)) { - logger.info("Skipping to proceed the payment because bounty payout is higher than paymentPermitMaxPrice"); - return { error: `Permit generation skipped since issue's bounty is higher than ${incentivesCalculation.paymentPermitMaxPrice}` }; - } - - // COMMENTERS REWARD HANDLER - if (conversationRewards.reward && conversationRewards.reward.length > 0) { - conversationRewards.reward.map(async (permit) => { - // Exclude issue creator from commenter rewards - if (permit.userId !== creatorReward.userId) { - rewardByUser.push({ - account: permit.account, - priceInEth: permit.priceInEth, - userId: permit.userId, - issueId: incentivesCalculation.issue.node_id, - type: [conversationRewards.title], - user: permit.user, - priceArray: [permit.priceInEth.toString()], - debug: permit.debug, - }); - } - }); - } - - // PULL REQUEST REVIEWERS REWARD HANDLER - if (pullRequestReviewersReward.reward && pullRequestReviewersReward.reward.length > 0) { - pullRequestReviewersReward.reward.map(async (permit) => { - // Exclude issue creator from commenter rewards - if (permit.userId !== creatorReward.userId) { - rewardByUser.push({ - account: permit.account, - priceInEth: permit.priceInEth, - userId: permit.userId, - issueId: incentivesCalculation.issue.node_id, - type: [pullRequestReviewersReward.title], - user: permit.user, - priceArray: [permit.priceInEth.toString()], - debug: permit.debug, - }); - } - }); - } - - // CREATOR REWARD HANDLER - // Generate permit for user if its not the same id as assignee - if (creatorReward && creatorReward.reward && creatorReward.reward[0].account !== "0x") { - rewardByUser.push({ - account: creatorReward.reward[0].account, - priceInEth: creatorReward.reward[0].priceInEth, - userId: creatorReward.userId, - issueId: incentivesCalculation.issue.node_id, - type: [creatorReward.title], - user: creatorReward.username, - priceArray: [creatorReward.reward[0].priceInEth.toString()], - debug: creatorReward.reward[0].debug, - }); - } else if (creatorReward && creatorReward.reward && creatorReward.reward[0].account === "0x") { - logger.info(`Skipping to generate a permit url for missing account. fallback: ${creatorReward.fallbackReward}`); - } - - // ASSIGNEE REWARD HANDLER - if (assigneeReward && assigneeReward.reward && assigneeReward.reward[0].account !== "0x") { - const permitComments = incentivesCalculation.comments.filter((content) => { - const permitUrlMatches = content.body.match(incentivesCalculation.claimUrlRegex); - if (!permitUrlMatches || permitUrlMatches.length < 2) return false; - else return true; - }); - - rewardByUser.push({ - account: assigneeReward.reward[0].account, - priceInEth: assigneeReward.reward[0].priceInEth, - userId: assigneeReward.userId, - issueId: incentivesCalculation.issue.node_id, - type: title, - user: assigneeReward.username, - priceArray: [assigneeReward.reward[0].priceInEth.toString()], - debug: assigneeReward.reward[0].debug, - }); - - if (permitComments.length > 0) { - logger.info(`Skip to generate a permit url because it has been already posted.`); - return { error: `Permit generation disabled because it was already posted to this issue.` }; - } - - if (assigneeReward.reward[0].penaltyAmount.gt(0)) { - await removePenalty( - incentivesCalculation.assignee.login, - incentivesCalculation.payload.repository.full_name, - incentivesCalculation.paymentToken, - incentivesCalculation.networkId.toString(), - assigneeReward.reward[0].penaltyAmount - ); - } - } - - // MERGE ALL REWARDS - const rewards = rewardByUser.reduce((acc, curr) => { - const existing = acc.find((item) => item.userId === curr.userId); - if (existing) { - existing.priceInEth = existing.priceInEth.add(curr.priceInEth); - existing.priceArray = existing.priceArray.concat(curr.priceArray); - existing.type = existing.type.concat(curr.type); - } else { - acc.push(curr); - } - return acc; - }, [] as RewardByUser[]); - - // sort rewards by price - rewards.sort((a, b) => { - return new Decimal(b.priceInEth).cmp(new Decimal(a.priceInEth)); - }); - - // CREATE PERMIT URL FOR EACH USER - for (const reward of rewards) { - if (!reward.user || !reward.userId) { - logger.info(`Skipping to generate a permit url for missing user. fallback: ${reward.user}`); - continue; - } - - const detailsValue = reward.priceArray - .map((price, i) => { - const separateTitle = reward.type[i]?.split("-"); - if (!separateTitle) return { title: "", subtitle: "", value: "" }; - return { title: separateTitle[0], subtitle: separateTitle[1], value: price }; - }) - // remove title if it's the same as the first one - .map((item, i, arr) => { - if (i === 0) return item; - if (item.title === arr[0].title) return { ...item, title: "" }; - return item; - }); - - const { reason, value } = await getWalletMultiplier(reward.user, incentivesCalculation.id?.toString()); - - // if reason is not "", then add multiplier to detailsValue and multiply the price - if (reason) { - detailsValue.push({ title: "Multiplier", subtitle: "Amount", value: value.toString() }); - detailsValue.push({ title: "", subtitle: "Reason", value: reason }); - - const multiplier = new Decimal(value); - const price = new Decimal(reward.priceInEth); - // add multiplier to the price - reward.priceInEth = price.mul(multiplier); - } - - const { payoutUrl, txData } = await generatePermit2Signature(reward.account, reward.priceInEth, reward.issueId, reward.userId?.toString()); - - const price = `${reward.priceInEth} ${incentivesCalculation.tokenSymbol.toUpperCase()}`; - - const comment = createDetailsTable(price, payoutUrl, reward.user, detailsValue, reward.debug); - - await savePermitToDB(Number(reward.userId), txData); - permitComment += comment; - - logger.info(`Skipping to generate a permit url for missing accounts. fallback: ${JSON.stringify(conversationRewards.fallbackReward)}`); - logger.info(`Skipping to generate a permit url for missing accounts. fallback: ${JSON.stringify(pullRequestReviewersReward.fallbackReward)}`); - } - - if (permitComment) await addCommentToIssue(permitComment.trim() + comments.promotionComment, issueNumber); - - await deleteLabel(incentivesCalculation.issueDetailed.priceLabel); - await addLabelToIssue("Permitted"); - - return { error: "" }; -}; diff --git a/src/handlers/payout/index.ts b/src/handlers/payout/index.ts deleted file mode 100644 index b6ab81422..000000000 --- a/src/handlers/payout/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./action"; -export * from "./post"; diff --git a/src/handlers/payout/post.ts b/src/handlers/payout/post.ts deleted file mode 100644 index e1ef60e76..000000000 --- a/src/handlers/payout/post.ts +++ /dev/null @@ -1,342 +0,0 @@ -import { getWalletAddress } from "../../adapters/supabase"; -import { getBotContext, getLogger } from "../../bindings"; -import { getAllIssueComments, getAllPullRequestReviews, getIssueDescription, parseComments } from "../../helpers"; -import { getLatestPullRequest, gitLinkedPrParser } from "../../helpers/parser"; -import { Incentives, MarkdownItem, Payload, UserType } from "../../types"; -import { RewardsResponse, commentParser } from "../comment"; -import Decimal from "decimal.js"; -import { bountyInfo } from "../wildcard"; -import { IncentivesCalculationResult } from "./action"; -import { BigNumber } from "ethers"; - -export interface CreatorCommentResult { - title: string; - account?: string | undefined; - amountInETH?: Decimal | undefined; - userId?: string | undefined; - tokenSymbol?: string | undefined; - node_id?: string | undefined; - user?: string | undefined; -} - -const ItemsToExclude: string[] = [MarkdownItem.BlockQuote]; -/** - * Incentivize the contributors based on their contribution. - * The default formula has been defined in https://github.com/ubiquity/ubiquibot/issues/272 - */ -export const calculateIssueConversationReward = async (calculateIncentives: IncentivesCalculationResult): Promise => { - const title = `Issue-Comments`; - const logger = getLogger(); - - const context = getBotContext(); - const payload = context.payload as Payload; - const issue = payload.issue; - - const assignees = issue?.assignees ?? []; - const assignee = assignees.length > 0 ? assignees[0] : undefined; - if (!assignee) { - logger.info("incentivizeComments: skipping payment permit generation because `assignee` is `undefined`."); - return { error: "incentivizeComments: skipping payment permit generation because `assignee` is `undefined`." }; - } - - const issueComments = await getAllIssueComments(calculateIncentives.issue.number, "full"); - logger.info(`Getting the issue comments done. comments: ${JSON.stringify(issueComments)}`); - const issueCommentsByUser: Record = {}; - for (const issueComment of issueComments) { - const user = issueComment.user; - if (user.type == UserType.Bot || user.login == assignee.login) continue; - const commands = commentParser(issueComment.body); - if (commands.length > 0) { - logger.info(`Skipping to parse the comment because it contains commands. comment: ${JSON.stringify(issueComment)}`); - continue; - } - if (!issueComment.body_html) { - logger.info(`Skipping to parse the comment because body_html is undefined. comment: ${JSON.stringify(issueComment)}`); - continue; - } - - // Store the comment along with user's login and node_id - if (!issueCommentsByUser[user.login]) { - issueCommentsByUser[user.login] = { id: user.id, comments: [] }; - } - issueCommentsByUser[user.login].comments.push(issueComment.body_html); - } - logger.info(`Filtering by the user type done. commentsByUser: ${JSON.stringify(issueCommentsByUser)}`); - - // The mapping between gh handle and amount in ETH - const fallbackReward: Record = {}; - - // array of awaiting permits to generate - const reward: { - account: string; - priceInEth: Decimal; - userId: number; - user: string; - penaltyAmount: BigNumber; - debug: Record; - }[] = []; - - for (const user of Object.keys(issueCommentsByUser)) { - const commentsByUser = issueCommentsByUser[user]; - const commentsByNode = await parseComments(commentsByUser.comments, ItemsToExclude); - const rewardValue = calculateRewardValue(commentsByNode, calculateIncentives.incentives); - if (rewardValue.sum.equals(0)) { - logger.info(`Skipping to generate a permit url because the reward value is 0. user: ${user}`); - continue; - } - logger.debug(`Comment parsed for the user: ${user}. comments: ${JSON.stringify(commentsByNode)}, sum: ${rewardValue.sum}`); - const account = await getWalletAddress(user); - const priceInEth = rewardValue.sum.mul(calculateIncentives.baseMultiplier); - if (priceInEth.gt(calculateIncentives.paymentPermitMaxPrice)) { - logger.info(`Skipping comment reward for user ${user} because reward is higher than payment permit max price`); - continue; - } - if (account) { - reward.push({ account, priceInEth, userId: commentsByUser.id, user, penaltyAmount: BigNumber.from(0), debug: rewardValue.sumByType }); - } else { - fallbackReward[user] = priceInEth; - } - } - - return { error: "", title, reward, fallbackReward }; -}; - -export const calculateIssueCreatorReward = async (incentivesCalculation: IncentivesCalculationResult): Promise => { - const title = `Issue-Creation`; - const logger = getLogger(); - - const issueDetailed = bountyInfo(incentivesCalculation.issue); - if (!issueDetailed.isBounty) { - logger.info(`incentivizeCreatorComment: its not a bounty`); - return { error: `incentivizeCreatorComment: its not a bounty` }; - } - - const assignees = incentivesCalculation.issue.assignees ?? []; - const assignee = assignees.length > 0 ? assignees[0] : undefined; - if (!assignee) { - logger.info("incentivizeCreatorComment: skipping payment permit generation because `assignee` is `undefined`."); - return { error: "incentivizeCreatorComment: skipping payment permit generation because `assignee` is `undefined`." }; - } - - const description = await getIssueDescription(incentivesCalculation.issue.number, "html"); - if (!description) { - logger.info(`Skipping to generate a permit url because issue description is empty. description: ${description}`); - return { error: `Skipping to generate a permit url because issue description is empty. description: ${description}` }; - } - logger.info(`Getting the issue description done. description: ${description}`); - const creator = incentivesCalculation.issue.user; - if (creator.type === UserType.Bot || creator.login === incentivesCalculation.issue.assignee) { - logger.info("Issue creator assigneed himself or Bot created this issue."); - return { error: "Issue creator assigneed himself or Bot created this issue." }; - } - - const result = await generatePermitForComments( - creator.login, - [description], - incentivesCalculation.issueCreatorMultiplier, - incentivesCalculation.incentives, - incentivesCalculation.paymentPermitMaxPrice - ); - - if (!result || !result.account || !result.amountInETH) { - throw new Error("Failed to generate permit for issue creator because of missing account or amountInETH"); - } - - return { - error: "", - title, - userId: creator.id, - username: creator.login, - reward: [ - { - priceInEth: result?.amountInETH ?? new Decimal(0), - account: result?.account, - userId: creator.id, - user: "", - penaltyAmount: BigNumber.from(0), - debug: {}, - }, - ], - }; -}; - -export const calculatePullRequestReviewsReward = async (incentivesCalculation: IncentivesCalculationResult): Promise => { - const logger = getLogger(); - const context = getBotContext(); - const title = "Review-Reviewer"; - - const linkedPullRequest = await gitLinkedPrParser({ - owner: incentivesCalculation.payload.repository.owner.login, - repo: incentivesCalculation.payload.repository.name, - issue_number: incentivesCalculation.issue.number, - }); - - const latestLinkedPullRequest = await getLatestPullRequest(linkedPullRequest); - - if (!latestLinkedPullRequest) { - logger.debug(`calculatePullRequestReviewsReward: No linked pull requests found`); - return { error: `calculatePullRequestReviewsReward: No linked pull requests found` }; - } - - const assignees = incentivesCalculation.issue?.assignees ?? []; - const assignee = assignees.length > 0 ? assignees[0] : undefined; - if (!assignee) { - logger.info("calculatePullRequestReviewsReward: skipping payment permit generation because `assignee` is `undefined`."); - return { error: "calculatePullRequestReviewsReward: skipping payment permit generation because `assignee` is `undefined`." }; - } - - const prReviews = await getAllPullRequestReviews(context, latestLinkedPullRequest.number, "full"); - const prComments = await getAllIssueComments(latestLinkedPullRequest.number, "full"); - logger.info(`Getting the PR reviews done. comments: ${JSON.stringify(prReviews)}`); - const prReviewsByUser: Record = {}; - for (const review of prReviews) { - const user = review.user; - if (!user) continue; - if (user.type == UserType.Bot || user.login == assignee) continue; - if (!review.body_html) { - logger.info(`calculatePullRequestReviewsReward: Skipping to parse the comment because body_html is undefined. comment: ${JSON.stringify(review)}`); - continue; - } - if (!prReviewsByUser[user.login]) { - prReviewsByUser[user.login] = { id: user.id, comments: [] }; - } - prReviewsByUser[user.login].comments.push(review.body_html); - } - - for (const comment of prComments) { - const user = comment.user; - if (!user) continue; - if (user.type == UserType.Bot || user.login == assignee) continue; - if (!comment.body_html) { - logger.info(`calculatePullRequestReviewsReward: Skipping to parse the comment because body_html is undefined. comment: ${JSON.stringify(comment)}`); - continue; - } - if (!prReviewsByUser[user.login]) { - prReviewsByUser[user.login] = { id: user.id, comments: [] }; - } - prReviewsByUser[user.login].comments.push(comment.body_html); - } - - logger.info(`calculatePullRequestReviewsReward: Filtering by the user type done. commentsByUser: ${JSON.stringify(prReviewsByUser)}`); - - // array of awaiting permits to generate - const reward: { - account: string; - priceInEth: Decimal; - userId: number; - user: string; - penaltyAmount: BigNumber; - debug: Record; - }[] = []; - - // The mapping between gh handle and amount in ETH - const fallbackReward: Record = {}; - - for (const user of Object.keys(prReviewsByUser)) { - const commentByUser = prReviewsByUser[user]; - const commentsByNode = await parseComments(commentByUser.comments, ItemsToExclude); - const rewardValue = calculateRewardValue(commentsByNode, incentivesCalculation.incentives); - if (rewardValue.sum.equals(0)) { - logger.info(`calculatePullRequestReviewsReward: Skipping to generate a permit url because the reward value is 0. user: ${user}`); - continue; - } - logger.info( - `calculatePullRequestReviewsReward: Comment parsed for the user: ${user}. comments: ${JSON.stringify(commentsByNode)}, sum: ${rewardValue.sum}` - ); - const account = await getWalletAddress(user); - const priceInEth = rewardValue.sum.mul(incentivesCalculation.baseMultiplier); - if (priceInEth.gt(incentivesCalculation.paymentPermitMaxPrice)) { - logger.info(`calculatePullRequestReviewsReward: Skipping comment reward for user ${user} because reward is higher than payment permit max price`); - continue; - } - - if (account) { - reward.push({ account, priceInEth, userId: commentByUser.id, user, penaltyAmount: BigNumber.from(0), debug: rewardValue.sumByType }); - } else { - fallbackReward[user] = priceInEth; - } - } - - logger.info(`calculatePullRequestReviewsReward: Permit url generated for pull request reviewers. reward: ${JSON.stringify(reward)}`); - logger.info(`calculatePullRequestReviewsReward: Skipping to generate a permit url for missing accounts. fallback: ${JSON.stringify(fallbackReward)}`); - - return { error: "", title, reward, fallbackReward }; -}; - -const generatePermitForComments = async ( - user: string, - comments: string[], - multiplier: number, - incentives: Incentives, - paymentPermitMaxPrice: number -): Promise => { - const logger = getLogger(); - const commentsByNode = await parseComments(comments, ItemsToExclude); - const rewardValue = calculateRewardValue(commentsByNode, incentives); - if (rewardValue.sum.equals(0)) { - logger.info(`No reward for the user: ${user}. comments: ${JSON.stringify(commentsByNode)}, sum: ${rewardValue}`); - return; - } - logger.debug(`Comment parsed for the user: ${user}. comments: ${JSON.stringify(commentsByNode)}, sum: ${rewardValue.sum}`); - const account = await getWalletAddress(user); - const amountInETH = rewardValue.sum.mul(multiplier); - if (amountInETH.gt(paymentPermitMaxPrice)) { - logger.info(`Skipping issue creator reward for user ${user} because reward is higher than payment permit max price`); - return; - } - if (account) { - return { account, amountInETH }; - } else { - return { account: "0x", amountInETH: new Decimal(0) }; - } -}; -/** - * @dev Calculates the reward values for a given comments. We'll improve the formula whenever we get the better one. - * - * @param comments - The comments to calculate the reward for - * @param incentives - The basic price table for reward calculation - * @returns - The reward value - */ -const calculateRewardValue = ( - comments: Record, - incentives: Incentives -): { sum: Decimal; sumByType: Record } => { - let sum = new Decimal(0); - const sumByType: Record = {}; - - for (const key of Object.keys(comments)) { - const value = comments[key]; - - // Initialize the sum for this key if it doesn't exist - if (!sumByType[key]) { - sumByType[key] = { - count: 0, - reward: new Decimal(0), - }; - } - - // if it's a text node calculate word count and multiply with the reward value - if (key == "#text") { - if (!incentives.comment.totals.word) { - continue; - } - const wordReward = new Decimal(incentives.comment.totals.word); - const wordCount = value.map((str) => str.trim().split(" ").length).reduce((totalWords, wordCount) => totalWords + wordCount, 0); - const reward = wordReward.mul(wordCount); - sumByType[key].count += wordCount; - sumByType[key].reward = wordReward; - sum = sum.add(reward); - } else { - if (!incentives.comment.elements[key]) { - continue; - } - const rewardValue = new Decimal(incentives.comment.elements[key]); - const reward = rewardValue.mul(value.length); - sumByType[key].count += value.length; - sumByType[key].reward = rewardValue; - sum = sum.add(reward); - } - } - - return { sum, sumByType }; -}; diff --git a/src/handlers/penalty/add-penalty.ts b/src/handlers/penalty/add-penalty.ts new file mode 100644 index 000000000..ce578ea08 --- /dev/null +++ b/src/handlers/penalty/add-penalty.ts @@ -0,0 +1,151 @@ +import { Context } from "../../types/context"; + +export async function addPenalty(context: Context) { + return context.logger.debug("Need to reimplement penalty system"); + // const { payload: _payload } = context; + // const { + // payout: { permitBaseUrl }, + // } = context.config; + // const logger = context.logger; + // const issue = context.payload.issue; + // const repository = context.payload.repository; + // if (!issue) return; + // try { + // // find permit comment from the bot + // const comments = await getAllIssueComments(issue.number); + // const claimUrlRegex = new RegExp(`\\((${permitBaseUrl}\\?claim=\\S+)\\)`); + // const permitCommentIdx = comments.findIndex((e) => e.user.type === "Bot" && e.body.match(claimUrlRegex)); + // if (permitCommentIdx === -1) { + // return; + // } + + // // extract permit amount and token + // const permitComment = comments[permitCommentIdx]; + // const permitUrl = permitComment.body.match(claimUrlRegex); + // if (!permitUrl || permitUrl.length < 2) { + // logger.error(`Permit URL not found`); + // return; + // } + // const url = new URL(permitUrl[1]); + // const claimBase64 = url.searchParams.get("claim"); + // if (!claimBase64) { + // logger.error(`Permit claim search parameter not found`); + // return; + // } + // let networkId = url.searchParams.get("network"); + // if (!networkId) { + // networkId = "1"; + // } + // const { rpc } = getPayoutConfigByNetworkId(Number(networkId)); + // let claim; + // try { + // claim = JSON.parse(Buffer.from(claimBase64, "base64").toString("utf-8")); + // } catch (err: unknown) { + // logger.error(`Error parsing claim: ${err}`); + // return; + // } + // const amount = BigNumber.from(claim.permit.permitted.amount); + // const formattedAmount = ethers.utils.formatUnits(amount, 18); + // const tokenAddress = claim.permit.permitted.token; + // const tokenSymbol = await getTokenSymbol(tokenAddress, rpc); + + // // find latest assignment before the permit comment + // const events = await getAllIssueAssignEvents(issue.number); + // if (events.length === 0) { + // logger.error(`No assignment found`); + // return; + // } + // const assignee = events[0].assignee.login; + + // if (parseFloat(formattedAmount) > 0) { + // // write penalty to db + // try { + // await addPenalty(assignee, repository.full_name, tokenAddress, networkId.toString(), amount); + // } catch (err) { + // logger.error(`Error writing penalty to db: ${err}`); + // return; + // } + + // await addCommentToIssue( + // `@${assignee} please be sure to review this conversation and implement any necessary fixes. Unless this is closed as completed, its payment of **${formattedAmount} ${tokenSymbol}** will be deducted from your next task.`, + // issue.number + // ); + // } else { + // logger.info(`Skipped penalty because amount is 0`); + // } + // } catch (err: unknown) { + // await addCommentToIssue(ErrorDiff(err), issue.number); + // } +} + +// export async function addPenalty( +// context: Context, +// username: string, +// repoName: string, +// tokenAddress: string, +// networkId: string, +// penalty: string +// ) { +// // const { supabase } = Runtime.getState().adapters; +// // const logger = context.logger; +// // const { error } = await supabase.rpc("add_penalty", { +// // _username: username, +// // _repository_name: repoName, +// // _token_address: tokenAddress, +// // _network_id: networkId, +// // _penalty_amount: penalty.toString(), +// // }); +// // logger.debug(`Adding penalty done, { data: ${JSON.stringify(error)}, error: ${JSON.stringify(error)} }`); +// // if (error) { +// // throw new Error(`Error adding penalty: ${error.message}`); +// // } +// } + +// export async function getPenalty( +// context: Context, +// username: string, +// repoName: string, +// tokenAddress: string, +// networkId: string +// ) { +// // const { supabase } = Runtime.getState().adapters; +// // const logger = context.logger; +// // const { data, error } = await supabase +// // .from("penalty") +// // .select("amount") +// // .eq("username", username) +// // .eq("repository_name", repoName) +// // .eq("network_id", networkId) +// // .eq("token_address", tokenAddress); +// // logger.debug(`Getting penalty done, { data: ${JSON.stringify(error)}, error: ${JSON.stringify(error)} }`); +// // if (error) { +// // throw new Error(`Error getting penalty: ${error.message}`); +// // } +// // if (data.length === 0) { +// // return BigNumber.from(0); +// // } +// // return BigNumber.from(data[0].amount); +// } + +// export async function removePenalty( +// context: Context, +// username: string, +// repoName: string, +// tokenAddress: string, +// networkId: string, +// penalty: string +// ) { +// // const { supabase } = Runtime.getState().adapters; +// // const logger = context.logger; +// // const { error } = await supabase.rpc("remove_penalty", { +// // _username: username, +// // _repository_name: repoName, +// // _network_id: networkId, +// // _token_address: tokenAddress, +// // _penalty_amount: penalty, +// // }); +// // logger.debug(`Removing penalty done, { data: ${JSON.stringify(error)}, error: ${JSON.stringify(error)} }`); +// // if (error) { +// // throw new Error(`Error removing penalty: ${error.message}`); +// // } +// } diff --git a/src/handlers/pricing/action.ts b/src/handlers/pricing/action.ts deleted file mode 100644 index 7e9673c6f..000000000 --- a/src/handlers/pricing/action.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { getBotConfig, getBotContext, getLogger } from "../../bindings"; -import { GLOBAL_STRINGS } from "../../configs"; -import { addCommentToIssue, addLabelToIssue, clearAllPriceLabelsOnIssue, createLabel, getLabel, calculateWeight, getAllLabeledEvents } from "../../helpers"; -import { Payload, UserType } from "../../types"; -import { handleLabelsAccess } from "../access"; -import { getTargetPriceLabel } from "../shared"; - -export const pricingLabelLogic = async (): Promise => { - const context = getBotContext(); - const config = getBotConfig(); - const logger = getLogger(); - const payload = context.payload as Payload; - if (!payload.issue) return; - const labels = payload.issue.labels; - const labelNames = labels.map((i) => i.name); - logger.info(`Checking if the issue is a parent issue.`); - if (payload.issue.body && isParentIssue(payload.issue.body)) { - logger.error("Identified as parent issue. Disabling price label."); - const issuePrices = labels.filter((label) => label.name.toString().startsWith("Price:")); - if (issuePrices.length) { - await addCommentToIssue(GLOBAL_STRINGS.skipPriceLabelGenerationComment, payload.issue.number); - await clearAllPriceLabelsOnIssue(); - } - return; - } - const valid = await handleLabelsAccess(); - - if (!valid && config.accessControl.label) { - return; - } - - const { assistivePricing } = config.mode; - const timeLabels = config.price.timeLabels.filter((item) => labels.map((i) => i.name).includes(item.name)); - const priorityLabels = config.price.priorityLabels.filter((item) => labels.map((i) => i.name).includes(item.name)); - - const minTimeLabel = timeLabels.length > 0 ? timeLabels.reduce((a, b) => (calculateWeight(a) < calculateWeight(b) ? a : b)).name : undefined; - const minPriorityLabel = priorityLabels.length > 0 ? priorityLabels.reduce((a, b) => (calculateWeight(a) < calculateWeight(b) ? a : b)).name : undefined; - - const targetPriceLabel = getTargetPriceLabel(minTimeLabel, minPriorityLabel); - - if (targetPriceLabel) { - const _targetPriceLabel = labelNames.find((name) => name.includes("Price") && name.includes(targetPriceLabel)); - - if (_targetPriceLabel) { - // get all issue events of type "labeled" and the event label includes Price - let labeledEvents = await getAllLabeledEvents(); - if (!labeledEvents) return; - - labeledEvents = labeledEvents.filter((event) => event.label?.name.includes("Price")); - if (!labeledEvents.length) return; - - // check if the latest price label has been added by a user - if (labeledEvents[labeledEvents.length - 1].actor?.type == UserType.User) { - logger.info(`Skipping... already exists`); - } else { - // add price label to issue becuase wrong price has been added by bot - logger.info(`Adding price label to issue`); - await clearAllPriceLabelsOnIssue(); - - const exist = await getLabel(targetPriceLabel); - - if (assistivePricing && !exist) { - logger.info(`${targetPriceLabel} doesn't exist on the repo, creating...`); - await createLabel(targetPriceLabel, "price"); - } - await addLabelToIssue(targetPriceLabel); - } - } else { - // add price if there is none - logger.info(`Adding price label to issue`); - await clearAllPriceLabelsOnIssue(); - - const exist = await getLabel(targetPriceLabel); - - if (assistivePricing && !exist) { - logger.info(`${targetPriceLabel} doesn't exist on the repo, creating...`); - await createLabel(targetPriceLabel, "price"); - } - await addLabelToIssue(targetPriceLabel); - } - } else { - await clearAllPriceLabelsOnIssue(); - logger.info(`Skipping action...`); - } -}; - -export const isParentIssue = (body: string) => { - const parentPattern = /-\s+\[( |x)\]\s+#\d+/; - return body.match(parentPattern); -}; diff --git a/src/handlers/pricing/handle-parent-issue.ts b/src/handlers/pricing/handle-parent-issue.ts new file mode 100644 index 000000000..590a63aef --- /dev/null +++ b/src/handlers/pricing/handle-parent-issue.ts @@ -0,0 +1,21 @@ +import { clearAllPriceLabelsOnIssue } from "../../helpers/issue"; +import { calculateLabelValue } from "../../helpers/shared"; +import { Context } from "../../types/context"; +import { Label } from "../../types/label"; + +export async function handleParentIssue(context: Context, labels: Label[]) { + const issuePrices = labels.filter((label) => label.name.toString().startsWith("Price:")); + if (issuePrices.length) { + await clearAllPriceLabelsOnIssue(context); + } + throw context.logger.error("Pricing is disabled on parent issues."); +} + +export function sortLabelsByValue(labels: Label[]) { + return labels.sort((a, b) => calculateLabelValue(a.name) - calculateLabelValue(b.name)); +} + +export function isParentIssue(body: string) { + const parentPattern = /-\s+\[( |x)\]\s+#\d+/; + return body.match(parentPattern); +} diff --git a/src/handlers/pricing/index.ts b/src/handlers/pricing/index.ts deleted file mode 100644 index 903db3cc9..000000000 --- a/src/handlers/pricing/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./action"; -export * from "./pre"; diff --git a/src/handlers/pricing/pre.ts b/src/handlers/pricing/pre.ts deleted file mode 100644 index 4d048d1ca..000000000 --- a/src/handlers/pricing/pre.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { getBotConfig, getLogger } from "../../bindings"; -import { calculateWeight, createLabel, listLabelsForRepo } from "../../helpers"; -import { calculateBountyPrice } from "../shared"; - -/** - * @dev This just checks all the labels in the config have been set in gh issue - * If there's something missing, they will be added - */ -export const validatePriceLabels = async (): Promise => { - const config = getBotConfig(); - const logger = getLogger(); - - const { assistivePricing } = config.mode; - - if (!assistivePricing) { - logger.info(`Assistive Pricing is disabled`); - return; - } - - const timeLabels = config.price.timeLabels.map((i) => i.name); - const priorityLabels = config.price.priorityLabels.map((i) => i.name); - const aiLabels: string[] = []; - for (const timeLabel of config.price.timeLabels) { - for (const priorityLabel of config.price.priorityLabels) { - const targetPrice = calculateBountyPrice(calculateWeight(timeLabel), calculateWeight(priorityLabel), config.price.baseMultiplier); - const targetPriceLabel = `Price: ${targetPrice} USD`; - aiLabels.push(targetPriceLabel); - } - } - - const neededLabels: string[] = [...timeLabels, ...priorityLabels]; - logger.debug(`Got needed labels for setting up price, neededLabels: ${neededLabels.toString()}`); - - // List all the labels for a repository - const repoLabels = await listLabelsForRepo(); - - // Get the missing labels - const missingLabels = neededLabels.filter((label) => !repoLabels.map((i) => i.name).includes(label)); - - // Create missing labels - if (missingLabels.length > 0) { - logger.info(`Creating missing labels: ${missingLabels}`); - await Promise.all(missingLabels.map((label) => createLabel(label))); - logger.info(`Creating missing labels done`); - } -}; diff --git a/src/handlers/pricing/pricing-label.ts b/src/handlers/pricing/pricing-label.ts new file mode 100644 index 000000000..0dd16371b --- /dev/null +++ b/src/handlers/pricing/pricing-label.ts @@ -0,0 +1,179 @@ +import { Context } from "../../types/context"; + +import { addLabelToIssue, clearAllPriceLabelsOnIssue } from "../../helpers/issue"; +import { createLabel, listLabelsForRepo } from "../../helpers/label"; +import { BotConfig } from "../../types/configuration-types"; +import { Label } from "../../types/label"; +import { GitHubPayload, UserType } from "../../types/payload"; +import { labelAccessPermissionsCheck } from "../access/labels-access"; +import { setPrice } from "../shared/pricing"; +import { handleParentIssue, isParentIssue, sortLabelsByValue } from "./handle-parent-issue"; + +export async function onLabelChangeSetPricing(context: Context): Promise { + const config = context.config; + const logger = context.logger; + const payload = context.event.payload as GitHubPayload; + if (!payload.issue) throw context.logger.fatal("Issue is not defined"); + + const labels = payload.issue.labels; + const labelNames = labels.map((i) => i.name); + + if (payload.issue.body && isParentIssue(payload.issue.body)) { + await handleParentIssue(context, labels); + return; + } + const hasPermission = await labelAccessPermissionsCheck(context); + if (!hasPermission) { + if (config.features.publicAccessControl.setLabel === false) { + throw logger.error("No public access control to set labels"); + } + throw logger.error("No permission to set labels"); + } + + const { assistivePricing: hasAssistivePricing } = config.features; + + if (!labels) throw logger.error(`No labels to calculate price`); + + // here we should make an exception if it was a price label that was just set to just skip this action + const isPayloadToSetPrice = payload.label?.name.includes("Price: "); + if (isPayloadToSetPrice) { + logger.info("This is setting the price label directly so skipping the rest of the action."); + + // make sure to clear all other price labels except for the smallest price label. + + const priceLabels = labels.filter((label) => label.name.includes("Price: ")); + const sortedPriceLabels = sortLabelsByValue(priceLabels); + const smallestPriceLabel = sortedPriceLabels.shift(); + const smallestPriceLabelName = smallestPriceLabel?.name; + if (smallestPriceLabelName) { + for (const label of sortedPriceLabels) { + await context.event.octokit.issues.removeLabel({ + owner: payload.repository.owner.login, + repo: payload.repository.name, + issue_number: payload.issue.number, + name: label.name, + }); + } + } + + return; + } + + const recognizedLabels = getRecognizedLabels(labels, config); + + if (!recognizedLabels.time.length || !recognizedLabels.priority.length) { + logger.error("No recognized labels to calculate price"); + await clearAllPriceLabelsOnIssue(context); + return; + } + + const minLabels = getMinLabels(recognizedLabels); + + if (!minLabels.time || !minLabels.priority) { + logger.error("No label to calculate price"); + return; + } + + if (!hasAssistivePricing) return; + + const targetPriceLabel = setPrice(context, minLabels.time, minLabels.priority); + + if (targetPriceLabel) { + await handleTargetPriceLabel(context, targetPriceLabel, labelNames); + } else { + await clearAllPriceLabelsOnIssue(context); + logger.info(`Skipping action...`); + } +} + +function getRecognizedLabels(labels: Label[], config: BotConfig) { + function isRecognizedLabel(label: Label, configLabels: string[]) { + return ( + (typeof label === "string" || typeof label === "object") && + configLabels.some((configLabel) => configLabel === label.name) + ); + } + + const recognizedTimeLabels: Label[] = labels.filter((label: Label) => isRecognizedLabel(label, config.labels.time)); + + const recognizedPriorityLabels: Label[] = labels.filter((label: Label) => + isRecognizedLabel(label, config.labels.priority) + ); + + return { time: recognizedTimeLabels, priority: recognizedPriorityLabels }; +} + +function getMinLabels(recognizedLabels: { time: Label[]; priority: Label[] }) { + const minTimeLabel = sortLabelsByValue(recognizedLabels.time).shift(); + const minPriorityLabel = sortLabelsByValue(recognizedLabels.priority).shift(); + + return { time: minTimeLabel, priority: minPriorityLabel }; +} + +async function handleTargetPriceLabel(context: Context, targetPriceLabel: string, labelNames: string[]) { + const _targetPriceLabel = labelNames.find((name) => name.includes("Price") && name.includes(targetPriceLabel)); + + if (_targetPriceLabel) { + await handleExistingPriceLabel(context, targetPriceLabel); + } else { + const allLabels = await listLabelsForRepo(context); + if (allLabels.filter((i) => i.name.includes(targetPriceLabel)).length === 0) { + await createLabel(context, targetPriceLabel, "price"); + } + await addPriceLabelToIssue(context, targetPriceLabel); + } +} + +async function handleExistingPriceLabel(context: Context, targetPriceLabel: string) { + const logger = context.logger; + let labeledEvents = await getAllLabeledEvents(context); + if (!labeledEvents) return logger.error("No labeled events found"); + + labeledEvents = labeledEvents.filter((event) => event.label?.name.includes("Price")); + if (!labeledEvents.length) return logger.error("No price labeled events found"); + + if (labeledEvents[labeledEvents.length - 1].actor?.type == UserType.User) { + logger.info(`Skipping... already exists`); + } else { + await addPriceLabelToIssue(context, targetPriceLabel); + } +} + +async function addPriceLabelToIssue(context: Context, targetPriceLabel: string) { + await clearAllPriceLabelsOnIssue(context); + await addLabelToIssue(context, targetPriceLabel); +} + +export async function labelExists(context: Context, name: string): Promise { + const payload = context.event.payload as GitHubPayload; + try { + await context.event.octokit.rest.issues.getLabel({ + owner: payload.repository.owner.login, + repo: payload.repository.name, + name, + }); + return true; + } catch (error) { + return false; + } +} + +async function getAllLabeledEvents(context: Context) { + const events = await getAllIssueEvents(context); + if (!events) return null; + return events.filter((event) => event.event === "labeled"); +} +async function getAllIssueEvents(context: Context) { + if (!context.payload.issue) return; + + try { + const events = await context.octokit.paginate(context.octokit.issues.listEvents, { + ...context.event.issue(), + per_page: 100, + }); + return events; + } catch (err: unknown) { + context.logger.fatal("Failed to fetch lists of events", err); + return []; + } +} diff --git a/src/handlers/pricing/sync-labels-to-config.ts b/src/handlers/pricing/sync-labels-to-config.ts new file mode 100644 index 000000000..ec058990a --- /dev/null +++ b/src/handlers/pricing/sync-labels-to-config.ts @@ -0,0 +1,51 @@ +import { createLabel, listLabelsForRepo } from "../../helpers/label"; +import { calculateLabelValue } from "../../helpers/shared"; +import { Context } from "../../types/context"; + +import { calculateTaskPrice } from "../shared/pricing"; + +// This just checks all the labels in the config have been set in gh issue +// If there's something missing, they will be added + +export async function syncPriceLabelsToConfig(context: Context) { + const config = context.config; + const logger = context.logger; + + const { + features: { assistivePricing: hasAssistivePricing }, + } = config; + + if (!hasAssistivePricing) { + logger.info(`Assistive pricing is disabled`); + return; + } + + const aiLabels: string[] = []; + for (const timeLabel of config.labels.time) { + for (const priorityLabel of config.labels.priority) { + const targetPrice = calculateTaskPrice( + context, + calculateLabelValue(timeLabel), + calculateLabelValue(priorityLabel), + config.payments.basePriceMultiplier + ); + const targetPriceLabel = `Price: ${targetPrice} USD`; + aiLabels.push(targetPriceLabel); + } + } + + const pricingLabels: string[] = [...config.labels.time, ...config.labels.priority]; + + // List all the labels for a repository + const allLabels = await listLabelsForRepo(context); + + // Get the missing labels + const missingLabels = pricingLabels.filter((label) => !allLabels.map((i) => i.name).includes(label)); + + // Create missing labels + if (missingLabels.length > 0) { + logger.info("Missing labels found, creating them", { missingLabels }); + await Promise.all(missingLabels.map((label) => createLabel(context, label))); + logger.info(`Creating missing labels done`); + } +} diff --git a/src/handlers/processors.ts b/src/handlers/processors.ts index 17bec49c7..21b7a8239 100644 --- a/src/handlers/processors.ts +++ b/src/handlers/processors.ts @@ -1,84 +1,90 @@ -import { GithubEvent, Handler, ActionHandler } from "../types"; -import { closePullRequestForAnIssue, commentWithAssignMessage } from "./assign"; -import { pricingLabelLogic, validatePriceLabels } from "./pricing"; -import { checkBountiesToUnassign, collectAnalytics, checkWeeklyUpdate } from "./wildcard"; -import { nullHandler } from "./shared"; -import { handleComment, issueClosedCallback, issueCreatedCallback, issueReopenedCallback } from "./comment"; -import { checkPullRequests } from "./assign/auto"; -import { createDevPoolPR } from "./pull-request"; -import { runOnPush, validateConfigChange } from "./push"; -import { findDuplicateOne } from "./issue"; -import { watchLabelChange } from "./label"; +import { GitHubEvent } from "../types/github-events"; +import { Handler, WildCardHandler } from "../types/handlers"; +import { assignCommandHandler, closePullRequestForAnIssue } from "./assign/assign-command-handler"; +import { checkPullRequests } from "./assign/check-pull-requests"; +import { commentCreated } from "./comment/comment-created"; +import { issueClosed } from "./comment/handlers/issue-closed"; +import { watchLabelChange } from "./label/label"; +import { addPenalty } from "./penalty/add-penalty"; +import { onLabelChangeSetPricing } from "./pricing/pricing-label"; +import { syncPriceLabelsToConfig } from "./pricing/sync-labels-to-config"; +import { createDevPoolPR } from "./pull-request/create-devpool-pr"; +import { checkModifiedBaseRate } from "./push/check-modified-base-rate"; +import { checkTasksToUnassign } from "./wildcard/unassign/check-tasks-to-unassign"; + +/** + * @dev + * pre and post handlers do not return a message to comment on the issue. their return type MUST BE `void` + * main action MUST return a message to comment on the issue. its return type MUST BE either `string` for plaintext or `LogReturn` for color to signal success, warning, or failure status + * TODO: all MUST receive `Context` as the only parameter + */ export const processors: Record = { - [GithubEvent.ISSUES_OPENED]: { - pre: [nullHandler], - action: [findDuplicateOne, issueCreatedCallback], - post: [nullHandler], + [GitHubEvent.ISSUES_OPENED]: { + pre: [], + action: [], + post: [], }, - [GithubEvent.ISSUES_REOPENED]: { - pre: [nullHandler], - action: [issueReopenedCallback], - post: [nullHandler], + [GitHubEvent.ISSUES_REOPENED]: { + pre: [], + action: [addPenalty], + post: [], }, - [GithubEvent.ISSUES_LABELED]: { - pre: [validatePriceLabels], - action: [pricingLabelLogic], - post: [nullHandler], + [GitHubEvent.ISSUES_LABELED]: { + pre: [syncPriceLabelsToConfig], + action: [], + post: [onLabelChangeSetPricing], }, - [GithubEvent.ISSUES_UNLABELED]: { - pre: [validatePriceLabels], - action: [pricingLabelLogic], - post: [nullHandler], + [GitHubEvent.ISSUES_UNLABELED]: { + pre: [syncPriceLabelsToConfig], + action: [], + post: [onLabelChangeSetPricing], }, - [GithubEvent.ISSUES_ASSIGNED]: { - pre: [nullHandler], - action: [commentWithAssignMessage], - post: [nullHandler], + [GitHubEvent.ISSUES_ASSIGNED]: { + pre: [], + action: [assignCommandHandler], + post: [], }, - [GithubEvent.ISSUES_UNASSIGNED]: { - pre: [nullHandler], + [GitHubEvent.ISSUES_UNASSIGNED]: { + pre: [], action: [closePullRequestForAnIssue], - post: [nullHandler], + post: [], }, - [GithubEvent.ISSUE_COMMENT_CREATED]: { - pre: [nullHandler], - action: [handleComment], - post: [nullHandler], + [GitHubEvent.ISSUE_COMMENT_CREATED]: { + pre: [], + action: [commentCreated], + post: [], }, - [GithubEvent.ISSUE_COMMENT_EDITED]: { - pre: [nullHandler], - action: [handleComment], - post: [nullHandler], + [GitHubEvent.ISSUE_COMMENT_EDITED]: { + pre: [], + action: [], + post: [], }, - [GithubEvent.ISSUES_CLOSED]: { - pre: [nullHandler], - action: [issueClosedCallback], - post: [nullHandler], + [GitHubEvent.ISSUES_CLOSED]: { + pre: [], + action: [issueClosed], + post: [], }, - [GithubEvent.PULL_REQUEST_OPENED]: { - pre: [nullHandler], + [GitHubEvent.PULL_REQUEST_OPENED]: { + pre: [], action: [checkPullRequests], - post: [nullHandler], + post: [], }, - [GithubEvent.INSTALLATION_ADDED_EVENT]: { - pre: [nullHandler], + [GitHubEvent.INSTALLATION_CREATED]: { + pre: [], action: [createDevPoolPR], - post: [nullHandler], + post: [], }, - [GithubEvent.PUSH_EVENT]: { - pre: [nullHandler], - action: [validateConfigChange, runOnPush], - post: [nullHandler], + [GitHubEvent.PUSH]: { + pre: [], + action: [], + post: [checkModifiedBaseRate], }, - [GithubEvent.LABEL_EDITED]: { - pre: [nullHandler], + [GitHubEvent.LABEL_EDITED]: { + pre: [], action: [watchLabelChange], - post: [nullHandler], + post: [], }, }; -/** - * @dev The handlers which will run on every event hooked - */ -export const wildcardProcessors: ActionHandler[] = [checkBountiesToUnassign, collectAnalytics, checkWeeklyUpdate]; +export const wildcardProcessors: WildCardHandler[] = [checkTasksToUnassign]; // The handlers which will run after every event diff --git a/src/handlers/pull-request/create-devpool-pr.ts b/src/handlers/pull-request/create-devpool-pr.ts index 08046bfbc..a2e18fd0c 100644 --- a/src/handlers/pull-request/create-devpool-pr.ts +++ b/src/handlers/pull-request/create-devpool-pr.ts @@ -1,22 +1,20 @@ -import { getBotContext, getLogger } from "../../bindings"; -import { GithubContent, Payload } from "../../types"; +import { Context } from "../../types/context"; +import { GithubContent, GitHubPayload } from "../../types/payload"; -export const createDevPoolPR = async () => { - const logger = getLogger(); - - const context = getBotContext(); - const payload = context.payload as Payload; +export async function createDevPoolPR(context: Context) { + const logger = context.logger; + const payload = context.event.payload as GitHubPayload; const devPoolOwner = "ubiquity"; const devPoolRepo = "devpool-directory"; if (!payload.repositories_added) { - return; + return logger.info("No repositories added"); } const repository = payload.repositories_added[0]; - logger.info(`New Install: ${repository.full_name}`); + logger.info("New Install: ", { repository: repository.full_name }); const [owner, repo] = repository.full_name.split("/"); @@ -25,14 +23,14 @@ export const createDevPoolPR = async () => { const baseRef = "development"; const path = "projects.json"; - const { data: branch } = await context.octokit.repos.getBranch({ + const { data: branch } = await context.event.octokit.repos.getBranch({ owner: devPoolOwner, repo: devPoolRepo, branch: "development", }); // Get the current projects json file - const { data: file } = await context.octokit.repos.getContent({ + const { data: file } = await context.event.octokit.repos.getContent({ owner: devPoolOwner, repo: devPoolRepo, path, @@ -52,7 +50,7 @@ export const createDevPoolPR = async () => { const mainSha = branch.commit.sha; // create branch from sha - await context.octokit.git.createRef({ + await context.event.octokit.git.createRef({ owner: devPoolOwner, repo: devPoolRepo, ref: `refs/heads/add-${owner}-${repo}`, @@ -61,7 +59,7 @@ export const createDevPoolPR = async () => { logger.info("Branch created on DevPool Directory"); - await context.octokit.repos.createOrUpdateFileContents({ + await context.event.octokit.repos.createOrUpdateFileContents({ owner: devPoolOwner, repo: devPoolRepo, path, @@ -72,14 +70,13 @@ export const createDevPoolPR = async () => { }); // create the pull request - await context.octokit.pulls.create({ + await context.event.octokit.pulls.create({ owner: devPoolOwner, repo: devPoolRepo, title: `Add ${repository.full_name} to repo`, head: branchName, base: baseRef, - body: "", }); - logger.info("Pull request created on DevPool Directory"); -}; + return logger.info("Pull request created on DevPool Directory"); +} diff --git a/src/handlers/pull-request/index.ts b/src/handlers/pull-request/index.ts deleted file mode 100644 index d0761df96..000000000 --- a/src/handlers/pull-request/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./create-devpool-pr"; diff --git a/src/handlers/push/check-modified-base-rate.ts b/src/handlers/push/check-modified-base-rate.ts new file mode 100644 index 000000000..418b7a762 --- /dev/null +++ b/src/handlers/push/check-modified-base-rate.ts @@ -0,0 +1,28 @@ +import { Context } from "../../types/context"; +import { GitHubPushPayload } from "../../types/payload"; +import { BASE_RATE_FILE, getCommitChanges, ZERO_SHA } from "./push"; +import { updateBaseRate } from "./update-base-rate"; + +export async function checkModifiedBaseRate(context: Context): Promise { + const logger = context.logger; + + const payload = context.event.payload as GitHubPushPayload; + + // if zero sha, push is a pr change + if (payload.before === ZERO_SHA) { + logger.info("Skipping push events. A new branch was created"); + } + + const changes = getCommitChanges(payload.commits); + + // skip if empty + if (changes && changes.length === 0) { + logger.info("No files were changed in the commits, so no action is required."); + } + + // check for modified or added files and check for specified file + if (changes.includes(BASE_RATE_FILE)) { + // update base rate + await updateBaseRate(context, BASE_RATE_FILE); + } +} diff --git a/src/handlers/push/index.ts b/src/handlers/push/index.ts deleted file mode 100644 index 340143439..000000000 --- a/src/handlers/push/index.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { getBotContext, getLogger } from "../../bindings"; -import { createCommitComment, getFileContent } from "../../helpers"; -import { CommitsPayload, PushPayload, WideConfigSchema } from "../../types"; -import { parseYAML } from "../../utils/private"; -import { updateBaseRate } from "./update-base"; -import { validate } from "../../utils/ajv"; - -const ZERO_SHA = "0000000000000000000000000000000000000000"; -const BASE_RATE_FILE = ".github/ubiquibot-config.yml"; - -function getCommitChanges(commits: CommitsPayload[]) { - const changes = []; - - for (const commit of commits) { - for (const modifiedFile of commit.modified) { - changes.push(modifiedFile); - } - for (const addedFile of commit.added) { - changes.push(addedFile); - } - } - return changes; -} - -export const runOnPush = async () => { - const logger = getLogger(); - - const context = getBotContext(); - const payload = context.payload as PushPayload; - - // if zero sha, push is a pr change - if (payload.before === ZERO_SHA) { - logger.debug("Skipping push events, not a master write"); - return; - } - - const changes = getCommitChanges(payload.commits); - - // skip if empty - if (changes && changes.length === 0) { - logger.debug("Skipping push events, file change empty"); - return; - } - - // check for modified or added files and check for specified file - if (changes.includes(BASE_RATE_FILE)) { - // update base rate - await updateBaseRate(context, payload, BASE_RATE_FILE); - } -}; - -export const validateConfigChange = async () => { - const logger = getLogger(); - - const context = getBotContext(); - const payload = context.payload as PushPayload; - - if (!payload.ref.startsWith("refs/heads/")) { - logger.debug("Skipping push events, not a branch"); - return; - } - - const changes = getCommitChanges(payload.commits); - - // skip if empty - if (changes && changes.length === 0) { - logger.debug("Skipping push events, file change empty"); - return; - } - - // check for modified or added files and check for specified file - if (changes.includes(BASE_RATE_FILE)) { - const commitSha = payload.commits.filter((commit) => commit.modified.includes(BASE_RATE_FILE) || commit.added.includes(BASE_RATE_FILE)).reverse()[0]?.id; - if (!commitSha) { - logger.debug("Skipping push events, commit sha not found"); - return; - } - - const configFileContent = await getFileContent( - payload.repository.owner.login, - payload.repository.name, - payload.ref.split("refs/heads/")[1], - BASE_RATE_FILE, - commitSha - ); - - if (configFileContent) { - const decodedConfig = Buffer.from(configFileContent, "base64").toString(); - const config = parseYAML(decodedConfig); - const { valid, error } = validate(WideConfigSchema, config); - if (!valid) { - await createCommitComment(`@${payload.sender.login} Config validation failed! ${error}`, commitSha, BASE_RATE_FILE); - } - } - } -}; diff --git a/src/handlers/push/push.ts b/src/handlers/push/push.ts new file mode 100644 index 000000000..ebd9acd93 --- /dev/null +++ b/src/handlers/push/push.ts @@ -0,0 +1,200 @@ +import { Context as ProbotContext } from "probot"; +import Runtime from "../../bindings/bot-runtime"; + +import { DefinedError } from "ajv"; +import { BotConfig, validateBotConfig } from "../../types/configuration-types"; +import { GitHubCommitsPayload, GitHubPayload, GitHubPushPayload } from "../../types/payload"; +import { parseYaml, transformConfig } from "../../utils/generate-configuration"; + +export const ZERO_SHA = "0000000000000000000000000000000000000000"; +export const BASE_RATE_FILE = ".github/ubiquibot-config.yml"; + +export function getCommitChanges(commits: GitHubCommitsPayload[]) { + const changes = [] as string[]; + + for (const commit of commits) { + for (const modifiedFile of commit.modified) { + changes.push(modifiedFile); + } + for (const addedFile of commit.added) { + changes.push(addedFile); + } + } + return changes; +} + +export async function validateConfigChange(context: ProbotContext) { + const runtime = Runtime.getState(); + const logger = runtime.logger; + + const payload = context.payload as GitHubPushPayload; + + if (!payload.ref.startsWith("refs/heads/")) { + logger.info("Skipping push events, not a branch"); + return; + } + + const changes = getCommitChanges(payload.commits); + + // skip if empty + if (changes && changes.length === 0) { + logger.info("Skipping push events as there are no file changes in the latest commit."); + return; + } + + // check for modified or added files and check for specified file + if (changes.includes(BASE_RATE_FILE)) { + const commitSha = payload.commits + .filter((commit) => commit.modified.includes(BASE_RATE_FILE) || commit.added.includes(BASE_RATE_FILE)) + .reverse()[0]?.id; + if (!commitSha) { + logger.info("Skipping push events, commit SHA not found"); + return; + } + + const configFileContent = await getFileContent( + context, + payload.repository.owner.login, + payload.repository.name, + payload.ref.split("refs/heads/")[1], + BASE_RATE_FILE, + commitSha + ); + + if (configFileContent) { + const decodedConfig = Buffer.from(configFileContent, "base64").toString(); + const config = parseYaml(decodedConfig); + const isValid = validateBotConfig(config); + let errorMsg: string | undefined; + + if (!isValid) { + const errMsg = generateValidationError(validateBotConfig.errors as DefinedError[]); + errorMsg = `@${payload.sender.login} ${errMsg}`; + } + + try { + transformConfig(config as BotConfig); + } catch (err) { + if (errorMsg) { + errorMsg += `\nConfig transformation failed:\n${err}`; + } else { + errorMsg = `@${payload.sender.login} Config transformation failed:\n${err}`; + } + } + + if (errorMsg) { + logger.info("Config validation failed!", errorMsg); + await createCommitComment(context, errorMsg, commitSha, BASE_RATE_FILE); + } else { + logger.info(`Config validation passed!`); + } + } + } else { + logger.info(`Skipping push events, file change doesn't include config file.`, changes); + } +} + +function generateValidationError(errors: DefinedError[]) { + const errorsWithoutStrict = errors.filter((error) => error.keyword !== "additionalProperties"); + const errorsOnlyStrict = errors.filter((error) => error.keyword === "additionalProperties"); + const isValid = errorsWithoutStrict.length === 0; + const errorMsg = isValid + ? "" + : errorsWithoutStrict.map((error) => error.instancePath.replaceAll("/", ".") + " " + error.message).join("\n"); + const warningMsg = + errorsOnlyStrict.length > 0 + ? "Warning! Unnecessary properties: \n" + + errorsOnlyStrict + .map( + (error) => + error.keyword === "additionalProperties" && + error.instancePath.replaceAll("/", ".") + "." + error.params.additionalProperty + ) + .join("\n") + : ""; + return `${isValid ? "Valid" : "Invalid"} configuration. \n${errorMsg}\n${warningMsg}`; +} + +async function createCommitComment( + context: ProbotContext, + body: string, + commitSha: string, + path?: string, + owner?: string, + repo?: string +) { + const payload = context.payload as GitHubPayload; + if (!owner) { + owner = payload.repository.owner.login; + } + if (!repo) { + repo = payload.repository.name; + } + + await context.octokit.rest.repos.createCommitComment({ + owner: owner, + repo: repo, + commit_sha: commitSha, + body: body, + path: path, + }); +} + +async function getFileContent( + context: ProbotContext, + owner: string, + repo: string, + branch: string, + filePath: string, + commitSha?: string +): Promise { + const runtime = Runtime.getState(); + const logger = runtime.logger; + + try { + if (!commitSha) { + // Get the latest commit of the branch + const branchData = await context.octokit.repos.getBranch({ + owner, + repo, + branch, + }); + commitSha = branchData.data.commit.sha; + } + + // Get the commit details + const commitData = await context.octokit.repos.getCommit({ + owner, + repo, + ref: commitSha, + }); + + // Find the file in the commit tree + const file = commitData.data.files ? commitData.data.files.find((file) => file.filename === filePath) : undefined; + if (file) { + // Retrieve the file tree + const tree = await context.octokit.git.getTree({ + owner, + repo, + tree_sha: commitData.data.commit.tree.sha, + recursive: "true", + }); + + // Find the previous file content in the tree + const file = tree.data.tree.find((item) => item.path === filePath); + if (file && file.sha) { + // Get the previous file content + const fileContent = await context.octokit.git.getBlob({ + owner, + repo, + file_sha: file.sha, + }); + return fileContent.data.content; + } + } + return null; + } catch (error: unknown) { + logger.debug("Error retrieving file content.", { error }); + return null; + } +} diff --git a/src/handlers/push/update-base-rate.ts b/src/handlers/push/update-base-rate.ts new file mode 100644 index 000000000..d1b8ca7c4 --- /dev/null +++ b/src/handlers/push/update-base-rate.ts @@ -0,0 +1,196 @@ +import { Context } from "../../types/context"; +import { Label } from "../../types/label"; +import { GitHubPushPayload } from "../../types/payload"; + +import { listLabelsForRepo } from "../../helpers/label"; +import { calculateLabelValue } from "../../helpers/shared"; +import { parseYaml } from "../../utils/generate-configuration"; +import { labelExists } from "../pricing/pricing-label"; +import { calculateTaskPrice } from "../shared/pricing"; + +export async function updateBaseRate(context: Context, filePath: string) { + const logger = context.logger; + // Get default branch from ref + const payload = context.event.payload as GitHubPushPayload; + const branch = payload.ref?.split("refs/heads/")[1]; + const owner = payload.repository.owner.login; + const repo = payload.repository.name; + + // get previous config + const previousFileContent = await getPreviousFileContent(context, owner, repo, branch, filePath); + + if (!previousFileContent) { + throw logger.fatal("Getting previous file content failed"); + } + const previousConfigRaw = Buffer.from(previousFileContent, "base64").toString(); + const previousConfigParsed = parseYaml(previousConfigRaw); + + if (!previousConfigParsed || !previousConfigParsed.payments.basePriceMultiplier) { + throw logger.error("No multiplier found in previous config"); + } + + const previousBaseRate = previousConfigParsed.payments.basePriceMultiplier; + + if (!previousBaseRate) { + throw logger.error("No base rate found in previous config"); + } + + // fetch all labels + const repoLabels = await listLabelsForRepo(context); + + if (repoLabels.length === 0) { + throw logger.error("No labels on this repo"); + } + + return await updateLabelsFromBaseRate(context, owner, repo, repoLabels as Label[], previousBaseRate); +} + +// Get the previous file content +async function getPreviousFileContent(context: Context, owner: string, repo: string, branch: string, filePath: string) { + const logger = context.logger; + + try { + // Get the latest commit of the branch + const branchData = await context.event.octokit.repos.getBranch({ + owner, + repo, + branch, + }); + const latestCommitSha = branchData.data.commit.sha; + + // Get the commit details + const commitData = await context.event.octokit.repos.getCommit({ + owner, + repo, + ref: latestCommitSha, + }); + + // Find the file in the commit tree + const file = commitData.data.files ? commitData.data.files.find((file) => file.filename === filePath) : undefined; + if (file) { + // Retrieve the previous file content from the commit's parent + const previousCommitSha = commitData.data.parents[0].sha; + const previousCommit = await context.event.octokit.git.getCommit({ + owner, + repo, + commit_sha: previousCommitSha, + }); + + // Retrieve the previous file tree + const previousTreeSha = previousCommit.data.tree.sha; + const previousTree = await context.event.octokit.git.getTree({ + owner, + repo, + tree_sha: previousTreeSha, + recursive: "true", + }); + + // Find the previous file content in the tree + const previousFile = previousTree.data.tree.find((item) => item.path === filePath); + if (previousFile && previousFile.sha) { + // Get the previous file content + const previousFileContent = await context.event.octokit.git.getBlob({ + owner, + repo, + file_sha: previousFile.sha, + }); + return previousFileContent.data.content; + } + } + return null; + } catch (error: unknown) { + logger.debug("Error retrieving previous file content.", { error }); + return null; + } +} +// Function to update labels based on the base rate difference +async function updateLabelsFromBaseRate( + context: Context, + owner: string, + repo: string, + labels: Label[], + previousBaseRate: number +) { + const logger = context.logger; + const config = context.config; + + const newLabels: string[] = []; + const previousLabels: string[] = []; + + for (const timeLabel of config.labels.time) { + for (const priorityLabel of config.labels.priority) { + const targetPrice = calculateTaskPrice( + context, + calculateLabelValue(timeLabel), + calculateLabelValue(priorityLabel), + config.payments.basePriceMultiplier + ); + const targetPriceLabel = `Price: ${targetPrice} USD`; + newLabels.push(targetPriceLabel); + + const previousTargetPrice = calculateTaskPrice( + context, + calculateLabelValue(timeLabel), + calculateLabelValue(priorityLabel), + previousBaseRate + ); + const previousTargetPriceLabel = `Price: ${previousTargetPrice} USD`; + previousLabels.push(previousTargetPriceLabel); + } + } + + const uniqueNewLabels = [...new Set(newLabels)]; + const uniquePreviousLabels = [...new Set(previousLabels)]; + + const labelsFiltered: string[] = labels.map((obj) => obj["name"]); + const usedLabels = uniquePreviousLabels.filter((value: string) => labelsFiltered.includes(value)); + + logger.debug("Got used labels: ", { usedLabels }); + + for (const label of usedLabels) { + if (label.startsWith("Price: ")) { + const labelData = labels.find((obj) => obj["name"] === label) as Label; + const index = uniquePreviousLabels.findIndex((obj) => obj === label); + + const doesExist = await labelExists(context, uniqueNewLabels[index]); + if (doesExist) { + // we have to delete first + logger.debug("Label already exists, deleting it", { label }); + await deleteLabel(context, uniqueNewLabels[index]); + } + + // we can update safely + await context.event.octokit.issues.updateLabel({ + owner, + repo, + name: label, + new_name: uniqueNewLabels[index], + color: labelData.color, + description: labelData.description, + headers: { + "X-GitHub-Api-Version": "2022-11-28", + }, + }); + + logger.debug("Label updated", { label, to: uniqueNewLabels[index] }); + } + } +} +async function deleteLabel(context: Context, label: string) { + const payload = context.payload; + try { + const response = await context.octokit.rest.search.issuesAndPullRequests({ + q: `repo:${payload.repository.owner.login}/${payload.repository.name} label:"${label}" state:open`, + }); + if (response.data.items.length === 0) { + //remove label + await context.octokit.rest.issues.deleteLabel({ + owner: payload.repository.owner.login, + repo: payload.repository.name, + name: label, + }); + } + } catch (e: unknown) { + context.logger.fatal("Deleting label failed!", e); + } +} diff --git a/src/handlers/push/update-base.ts b/src/handlers/push/update-base.ts deleted file mode 100644 index da67c8e6c..000000000 --- a/src/handlers/push/update-base.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Context } from "probot"; -import { getLogger } from "../../bindings"; -import { getPreviousFileContent, listLabelsForRepo, updateLabelsFromBaseRate } from "../../helpers"; -import { Label, PushPayload } from "../../types"; -import { parseYAML } from "../../utils/private"; - -export const updateBaseRate = async (context: Context, payload: PushPayload, filePath: string) => { - const logger = getLogger(); - // Get default branch from ref - const branch = payload.ref?.split("refs/heads/")[1]; - const owner = payload.repository.owner.login; - const repo = payload.repository.name; - - // get previous config - const preFileContent = await getPreviousFileContent(owner, repo, branch, filePath); - - if (!preFileContent) { - logger.debug("Getting previous file content failed"); - return; - } - const previousContent = Buffer.from(preFileContent, "base64").toString(); - const previousConfig = await parseYAML(previousContent); - - if (!previousConfig || !previousConfig["priceMultiplier"]) { - logger.debug("No multiplier found in file object"); - return; - } - - const previousBaseRate = previousConfig["priceMultiplier"]; - - // fetch all labels - const repoLabels = await listLabelsForRepo(); - - if (repoLabels.length === 0) { - logger.debug("No labels on this repo"); - return; - } - - await updateLabelsFromBaseRate(owner, repo, context, repoLabels as Label[], previousBaseRate); -}; diff --git a/src/handlers/shared/handler.ts b/src/handlers/shared/handler.ts deleted file mode 100644 index 3102be164..000000000 --- a/src/handlers/shared/handler.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { getLogger } from "../../bindings"; -import { ActionHandler } from "../../types"; - -export const nullHandler: ActionHandler = async (): Promise => { - // ToDo: This is just a null handler to do nothing. just needed for mockup - // This would be replaced with the meaningful handler once its feature determined - - const logger = getLogger(); - logger.debug(`Running handler, name: ${nullHandler.name}`); -}; diff --git a/src/handlers/shared/index.ts b/src/handlers/shared/index.ts deleted file mode 100644 index a0c9d7fd7..000000000 --- a/src/handlers/shared/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./handler"; -export * from "./pricing"; - -export const deadLinePrefix = "The time limit for this bounty is on"; diff --git a/src/handlers/shared/pricing.ts b/src/handlers/shared/pricing.ts index 0a543bc7c..d8e0f7505 100644 --- a/src/handlers/shared/pricing.ts +++ b/src/handlers/shared/pricing.ts @@ -1,24 +1,37 @@ -import { getBotConfig } from "../../bindings"; -import { calculateWeight } from "../../helpers"; +import { calculateLabelValue } from "../../helpers/shared"; +import { Context } from "../../types/context"; +import { Label } from "../../types/label"; -export const calculateBountyPrice = (timeValue: number, priorityValue: number, baseValue?: number): number => { - const botConfig = getBotConfig(); - const base = baseValue ?? botConfig.price.baseMultiplier; +export function calculateTaskPrice( + context: Context, + timeValue: number, + priorityValue: number, + baseValue?: number +): number { + const base = baseValue ?? context.config.payments.basePriceMultiplier; const priority = priorityValue / 10; // floats cause bad math const price = 1000 * base * timeValue * priority; return price; -}; - -export const getTargetPriceLabel = (timeLabel: string | undefined, priorityLabel: string | undefined): string | undefined => { - const botConfig = getBotConfig(); - let targetPriceLabel: string | undefined = undefined; - if (timeLabel && priorityLabel) { - const timeWeight = calculateWeight(botConfig.price.timeLabels.find((item) => item.name === timeLabel)); - const priorityWeight = calculateWeight(botConfig.price.priorityLabels.find((item) => item.name === priorityLabel)); - if (timeWeight && priorityWeight) { - const bountyPrice = calculateBountyPrice(timeWeight, priorityWeight); - targetPriceLabel = `Price: ${bountyPrice} USD`; - } - } - return targetPriceLabel; -}; +} + +export function setPrice(context: Context, timeLabel: Label, priorityLabel: Label) { + const logger = context.logger; + const { labels } = context.config; + + if (!timeLabel || !priorityLabel) throw logger.error("Time or priority label is not defined"); + + const recognizedTimeLabels = labels.time.find((configLabel) => configLabel === timeLabel.name); + if (!recognizedTimeLabels) throw logger.error("Time label is not recognized"); + + const recognizedPriorityLabels = labels.priority.find((configLabel) => configLabel === priorityLabel.name); + if (!recognizedPriorityLabels) throw logger.error("Priority label is not recognized"); + + const timeValue = calculateLabelValue(recognizedTimeLabels); + if (!timeValue) throw logger.error("Time value is not defined"); + + const priorityValue = calculateLabelValue(recognizedPriorityLabels); + if (!priorityValue) throw logger.error("Priority value is not defined"); + + const taskPrice = calculateTaskPrice(context, timeValue, priorityValue); + return `Price: ${taskPrice} USD`; +} diff --git a/src/handlers/shared/structured-metadata.ts b/src/handlers/shared/structured-metadata.ts new file mode 100644 index 000000000..548bbd4c6 --- /dev/null +++ b/src/handlers/shared/structured-metadata.ts @@ -0,0 +1,59 @@ +import { LogLevel } from "ubiquibot-logger/pretty-logs"; +import { COMMIT_HASH } from "../../commit-hash"; + +function createStructuredMetadata(className: string, metadata: any) { + const jsonPretty = JSON.stringify(metadata, null, 2); + const stackLine = new Error().stack?.split("\n")[2] ?? ""; + const caller = stackLine.match(/at (\S+)/)?.[1] ?? ""; + const revision = COMMIT_HASH?.substring(0, 7) ?? null; + const ubiquityMetadataHeader = `"].join("\n"); + + if (metadata?.logMessage?.type === LogLevel.FATAL) { + // if the log message is fatal, then we want to show the metadata + metadataSerialized = [metadataSerializedVisible, metadataSerializedHidden].join("\n"); + } else { + // otherwise we want to hide it + metadataSerialized = metadataSerializedHidden; + } + + return metadataSerialized; +} + +function parseStructuredMetadata(comment: string) { + const regex = //gs; + + const match = regex.exec(comment); + + if (!match) { + return null; + } + + const [, type, caller, revision, jsonString] = match; + + let metadata; + try { + // TODO: fix metadata writing to encode html comments inside json without the html parser getting confused + metadata = JSON.parse(jsonString.trim()); + } catch (error) { + console.trace(jsonString); + console.error("Failed to parse JSON:", error); + + return null; + } + + return { + className: type.trim(), + caller: caller.trim(), + revision: revision.trim(), + metadata, + }; +} + +export default { + create: createStructuredMetadata, + parse: parseStructuredMetadata, +}; diff --git a/src/handlers/wildcard/analytics.ts b/src/handlers/wildcard/analytics.ts index df877f070..14be81657 100644 --- a/src/handlers/wildcard/analytics.ts +++ b/src/handlers/wildcard/analytics.ts @@ -1,110 +1,40 @@ -import { getMaxIssueNumber, upsertIssue, upsertUser } from "../../adapters/supabase"; -import { getBotConfig, getLogger } from "../../bindings"; -import { listIssuesForRepo, getUser, calculateWeight } from "../../helpers"; -import { Issue, IssueType, User, UserProfile } from "../../types"; - -/** - * Checks the issue whether it's a bounty for hunters or an issue for not - * @param issue - The issue object - * @returns If bounty - true, If issue - false - */ -export const bountyInfo = ( - issue: Issue +import { calculateLabelValue } from "../../helpers/shared"; +import { Context } from "../../types/context"; +import { GitHubIssue } from "../../types/payload"; + +// Checks the issue whether it's an open task for public self assignment +export function taskPaymentMetaData( + context: Context, + issue: GitHubIssue ): { - isBounty: boolean; - timelabel: string | undefined; - priorityLabel: string | undefined; - priceLabel: string | undefined; -} => { - const config = getBotConfig(); - const labels = issue.labels; + eligibleForPayment: boolean; + timeLabel: string | null; + priorityLabel: string | null; + priceLabel: string | null; +} { + const { labels } = context.config; + + const timeLabels = labels.time.filter((configLabel) => issue.labels.map((i) => i.name).includes(configLabel)); + const priorityLabels = labels.priority.filter((configLabel) => issue.labels.map((i) => i.name).includes(configLabel)); - const timeLabels = config.price.timeLabels.filter((item) => labels.map((i) => i.name).includes(item.name)); - const priorityLabels = config.price.priorityLabels.filter((item) => labels.map((i) => i.name).includes(item.name)); + const isTask = timeLabels.length > 0 && priorityLabels.length > 0; - const isBounty = timeLabels.length > 0 && priorityLabels.length > 0; + const minTimeLabel = + timeLabels.length > 0 + ? timeLabels.reduce((a, b) => (calculateLabelValue(a) < calculateLabelValue(b) ? a : b)) + : null; - const minTimeLabel = timeLabels.length > 0 ? timeLabels.reduce((a, b) => (calculateWeight(a) < calculateWeight(b) ? a : b)).name : undefined; - const minPriorityLabel = priorityLabels.length > 0 ? priorityLabels.reduce((a, b) => (calculateWeight(a) < calculateWeight(b) ? a : b)).name : undefined; + const minPriorityLabel = + priorityLabels.length > 0 + ? priorityLabels.reduce((a, b) => (calculateLabelValue(a) < calculateLabelValue(b) ? a : b)) + : null; - const priceLabel = labels.find((label) => label.name.includes("Price"))?.name; + const priceLabel = issue.labels.find((label) => label.name.includes("Price"))?.name || null; return { - isBounty, - timelabel: minTimeLabel, + eligibleForPayment: isTask, + timeLabel: minTimeLabel, priorityLabel: minPriorityLabel, priceLabel, }; -}; - -/** - * Collects all the analytics information by scanning the issues opened | closed - */ -export const collectAnalytics = async (): Promise => { - const logger = getLogger(); - const { - mode: { disableAnalytics }, - } = getBotConfig(); - if (disableAnalytics) { - logger.info(`Skipping to collect analytics, reason: mode=${disableAnalytics}`); - return; - } - logger.info("Collecting analytics information..."); - const maximumIssueNumber = await getMaxIssueNumber(); - - let fetchDone = false; - const perPage = 30; - let curPage = 1; - while (!fetchDone) { - const issues = await listIssuesForRepo(IssueType.ALL, perPage, curPage); - - // need to skip checking the closed issues already stored in the db and filter them by doing a sanitation checks. - // sanitation checks would be basically checking labels of the issue - // whether the issue has both `priority` label and `timeline` label - const bounties = issues.filter((issue) => bountyInfo(issue as Issue).isBounty); - - // collect assignees from both type of issues (opened/closed) - const assignees = bounties.filter((bounty) => bounty.assignee).map((bounty) => bounty.assignee as User); - - // remove duplication by assignee - const tmp = assignees.map((i) => i.login); - const assigneesToUpsert = assignees.filter((assignee, pos) => tmp.indexOf(assignee.login) == pos); - const userProfilesToUpsert = await Promise.all( - assigneesToUpsert.map(async (assignee) => { - const res = await getUser(assignee.login); - return res as UserProfile; - }) - ); - - logger.info( - `Upserting users: ${userProfilesToUpsert - .filter((i) => i.login) - .map((i) => i.login) - .toString()}` - ); - - await Promise.all(userProfilesToUpsert.map((i) => upsertUser(i))); - - // No need to update the record for the bounties already closed - const bountiesToUpsert = bounties.filter((bounty) => (bounty.state === IssueType.CLOSED ? bounty.number > maximumIssueNumber : true)); - logger.info(`Upserting bounties: ${bountiesToUpsert.map((i) => i.title).toString()}`); - await Promise.all( - bountiesToUpsert.map((i) => { - const additions = bountyInfo(i as Issue); - if (additions.timelabel && additions.priorityLabel && additions.priceLabel) - return upsertIssue(i as Issue, { - labels: { - timeline: additions.timelabel, - priority: additions.priorityLabel, - price: additions.priceLabel, - }, - }); - return undefined; - }) - ); - - if (issues.length < perPage) fetchDone = true; - else curPage++; - } - logger.info("Collecting analytics finished..."); -}; +} diff --git a/src/handlers/wildcard/index.ts b/src/handlers/wildcard/index.ts deleted file mode 100644 index ff4f7dafa..000000000 --- a/src/handlers/wildcard/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./unassign"; -export * from "./analytics"; -export * from "./weekly"; diff --git a/src/handlers/wildcard/unassign.ts b/src/handlers/wildcard/unassign.ts deleted file mode 100644 index ec057ce73..000000000 --- a/src/handlers/wildcard/unassign.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { getBotConfig, getBotContext, getLogger } from "../../bindings"; -import { GLOBAL_STRINGS } from "../../configs/strings"; -import { - addCommentToIssue, - getAllIssueComments, - getCommitsOnPullRequest, - getOpenedPullRequestsForAnIssue, - getReviewRequests, - listAllIssuesForRepo, - removeAssignees, -} from "../../helpers"; -import { Comment, Issue, IssueType, Payload, UserType } from "../../types"; -import { deadLinePrefix } from "../shared"; - -/** - * @dev Check out the bounties which haven't been completed within the initial timeline - * and try to release the bounty back to dev pool - */ -export const checkBountiesToUnassign = async () => { - const logger = getLogger(); - logger.info(`Getting all the issues...`); - - // List all the issues in the repository. It may include `pull_request` - // because GitHub's REST API v3 considers every pull request an issue - const issues_opened = await listAllIssuesForRepo(IssueType.OPEN); - - const assigned_issues = issues_opened.filter((issue) => issue.assignee); - - // Checking the bounties in parallel - const res = await Promise.all(assigned_issues.map(async (issue) => checkBountyToUnassign(issue as Issue))); - logger.info(`Checking expired bounties done! total: ${res.length}, unassigned: ${res.filter((i) => i).length}`); -}; - -const checkBountyToUnassign = async (issue: Issue): Promise => { - const context = getBotContext(); - const payload = context.payload as Payload; - const logger = getLogger(); - const { - unassign: { followUpTime, disqualifyTime }, - } = getBotConfig(); - logger.info(`Checking the bounty to unassign, issue_number: ${issue.number}`); - const { unassignComment, askUpdate } = GLOBAL_STRINGS; - const assignees = issue.assignees.map((i) => i.login); - const comments = await getAllIssueComments(issue.number); - if (!comments || comments.length == 0) return false; - - const askUpdateComments = comments - .filter((comment: Comment) => comment.body.includes(askUpdate)) - .sort((a: Comment, b: Comment) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()); - - const lastAskTime = askUpdateComments.length > 0 ? new Date(askUpdateComments[0].created_at).getTime() : new Date(issue.created_at).getTime(); - const curTimestamp = new Date().getTime(); - const lastActivity = await lastActivityTime(issue, comments); - const passedDuration = curTimestamp - lastActivity.getTime(); - const pullRequest = await getOpenedPullRequestsForAnIssue(issue.number, issue.assignee.login); - - if (pullRequest.length > 0) { - const reviewRequests = await getReviewRequests(context, pullRequest[0].number, payload.repository.owner.login, payload.repository.name); - if (!reviewRequests || reviewRequests.users?.length > 0) { - return false; - } - } - - if (passedDuration >= disqualifyTime || passedDuration >= followUpTime) { - if (passedDuration >= disqualifyTime) { - logger.info( - `Unassigning... lastActivityTime: ${lastActivity.getTime()}, curTime: ${curTimestamp}, passedDuration: ${passedDuration}, followUpTime: ${followUpTime}, disqualifyTime: ${disqualifyTime}` - ); - // remove assignees from the issue - await removeAssignees(issue.number, assignees); - await addCommentToIssue(`@${assignees[0]} - ${unassignComment} \nLast activity time: ${lastActivity}`, issue.number); - - return true; - } else if (passedDuration >= followUpTime) { - logger.info( - `Asking for updates... lastActivityTime: ${lastActivity.getTime()}, curTime: ${curTimestamp}, passedDuration: ${passedDuration}, followUpTime: ${followUpTime}, disqualifyTime: ${disqualifyTime}` - ); - - if (lastAskTime > lastActivity.getTime()) { - logger.info( - `Skipping posting an update message cause its been already asked, lastAskTime: ${lastAskTime}, lastActivityTime: ${lastActivity.getTime()}` - ); - } else { - await addCommentToIssue( - `${askUpdate} @${assignees[0]}? If you would like to release the bounty back to the DevPool, please comment \`/stop\` \nLast activity time: ${lastActivity}`, - issue.number - ); - } - } - } - - return false; -}; - -const lastActivityTime = async (issue: Issue, comments: Comment[]): Promise => { - const logger = getLogger(); - logger.info(`Checking the latest activity for the issue, issue_number: ${issue.number}`); - const assignees = issue.assignees.map((i) => i.login); - const activities: Date[] = [new Date(issue.created_at)]; - - const lastAssignCommentOfHunter = comments - .filter((comment) => comment.user.type === UserType.Bot && comment.body.includes(assignees[0]) && comment.body.includes(deadLinePrefix)) - .sort((a: Comment, b: Comment) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()); - if (lastAssignCommentOfHunter.length > 0) activities.push(new Date(lastAssignCommentOfHunter[0].created_at)); - - // get last comment on the issue - const lastCommentsOfHunterForIssue = comments - .filter((comment) => assignees.includes(comment.user.login)) - .sort((a: Comment, b: Comment) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()); - - if (lastCommentsOfHunterForIssue.length > 0) activities.push(new Date(lastCommentsOfHunterForIssue[0].created_at)); - - const openedPrsForIssue = await getOpenedPullRequestsForAnIssue(issue.number, assignees[0]); - const pr = openedPrsForIssue.length > 0 ? openedPrsForIssue[0] : undefined; - // get last commit and last comment on the linked pr - if (pr) { - const commits = (await getCommitsOnPullRequest(pr.number)) - .filter((it) => it.commit.committer?.date) - .sort((a, b) => new Date(b.commit.committer?.date ?? 0).getTime() - new Date(a.commit.committer?.date ?? 0).getTime()); - const prComments = (await getAllIssueComments(pr.number)) - .filter((comment) => comment.user.login === assignees[0]) - .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()); - - if (commits.length > 0) activities.push(new Date(commits[0].commit.committer?.date ?? 0)); - if (prComments.length > 0) activities.push(new Date(prComments[0].created_at)); - } - - activities.sort((a, b) => b.getTime() - a.getTime()); - - return activities[0]; -}; diff --git a/src/handlers/wildcard/unassign/aggregate-assignee-activity.ts b/src/handlers/wildcard/unassign/aggregate-assignee-activity.ts new file mode 100644 index 000000000..76717d1ac --- /dev/null +++ b/src/handlers/wildcard/unassign/aggregate-assignee-activity.ts @@ -0,0 +1,53 @@ +import { getLinkedPullRequests } from "../../../helpers/get-linked-pull-requests"; +import { Commit } from "../../../types/commit"; +import { Context } from "../../../types/context"; +import { getAllCommitsFromPullRequest } from "./get-all-commits-from-pull-request"; +import { getAllEvents } from "./get-all-events"; + +export async function aggregateAssigneeActivity({ + context, + login, + name, + number, + assignees, +}: AggregateAssigneeActivity) { + const allEvents = await getAllEvents({ context, owner: login, repo: name, issueNumber: number }); + const assigneeEvents = allEvents.filter((event) => assignees.includes(event.actor.login)); // Filter all events by assignees + + // check the linked pull request and then check that pull request's commits + const linkedPullRequests = await getLinkedPullRequests(context, { owner: login, repository: name, issue: number }); + + const allCommits = [] as Commit[]; + for (const pullRequest of linkedPullRequests) { + try { + const commits = await getAllCommitsFromPullRequest({ + context, + owner: login, + repo: name, + pullNumber: pullRequest.number, + }); + allCommits.push(...commits); + } catch (error) { + console.trace({ error }); + // return []; + } + } + + // DONE: check commits - e.g. https://api.github.com/repos/ubiquity/ubiquibot/pulls/644/commits?per_page=100 + // Filter all commits by assignees + const assigneeCommits = allCommits.filter((commit) => { + const name = commit.author?.login || commit.commit.committer?.name; + if (!name) { + return false; + } + assignees.includes(name); + }); + return { assigneeEvents, assigneeCommits }; +} +interface AggregateAssigneeActivity { + context: Context; + login: string; + name: string; + number: number; + assignees: string[]; +} diff --git a/src/handlers/wildcard/unassign/assign-event-found.ts b/src/handlers/wildcard/unassign/assign-event-found.ts new file mode 100644 index 000000000..acf51154e --- /dev/null +++ b/src/handlers/wildcard/unassign/assign-event-found.ts @@ -0,0 +1,57 @@ +import { Logs } from "ubiquibot-logger"; +import { Context } from "../../../types/context"; +import { GitHubAssignEvent, GitHubUser } from "../../../types/payload"; +import { disqualifyIdleAssignees } from "./disqualify-idle-assignees"; +import { remindNonEliminatedAssignees } from "./remind-non-eliminated-assignees"; + +export async function assignEventFound({ + latestAssignEvent, + logger, + assignees, + disqualifiedAssignees, + context, + login, + name, + number, + taskDisqualifyDuration, + activeAssigneesInDisqualifyDuration, + activeAssigneesInFollowUpDuration, +}: AssignEventFoundParams) { + const latestAssignEventTime = new Date(latestAssignEvent.created_at).getTime(); + logger.debug("Latest assign event time", { latestAssignEventTime }); + const now = Date.now(); + const assigneesWithinGracePeriod = assignees.filter(() => now - latestAssignEventTime < taskDisqualifyDuration); + const assigneesOutsideGracePeriod = assignees.filter((assignee) => !assigneesWithinGracePeriod.includes(assignee)); + disqualifiedAssignees = await disqualifyIdleAssignees(context, { + assignees: assigneesOutsideGracePeriod.map((assignee) => assignee.login), + activeAssigneesInDisqualifyDuration, + login, + name, + number, + }); + + // DONE: follow up with those who are in `assignees` and not inside of `disqualifiedAssignees` or `activeAssigneesInFollowUpDuration` + await remindNonEliminatedAssignees(context, { + assignees: assigneesOutsideGracePeriod.map((assignee) => assignee.login), + disqualifiedAssignees, + activeAssigneesInFollowUpDuration, + login, + name, + number, + taskDisqualifyDuration, + }); + return disqualifiedAssignees; +} +interface AssignEventFoundParams { + latestAssignEvent: GitHubAssignEvent; + logger: Logs; + assignees: GitHubUser[]; + context: Context; + login: string; + name: string; + number: number; + disqualifiedAssignees: null | string[]; + taskDisqualifyDuration: number; + activeAssigneesInDisqualifyDuration: string[]; + activeAssigneesInFollowUpDuration: string[]; +} diff --git a/src/handlers/wildcard/unassign/check-if-follow-up-already-posted.ts b/src/handlers/wildcard/unassign/check-if-follow-up-already-posted.ts new file mode 100644 index 000000000..d7d98858c --- /dev/null +++ b/src/handlers/wildcard/unassign/check-if-follow-up-already-posted.ts @@ -0,0 +1,35 @@ +import { Context } from "../../../types/context"; + +export async function checkIfFollowUpAlreadyPosted( + context: Context, + login: string, + name: string, + number: number, + followUpMessage: string, + disqualificationPeriod: number +) { + const comments = await context.event.octokit.rest.issues.listComments({ + owner: login, + repo: name, + issue_number: number, + }); + + // Get the current time + const now = new Date().getTime(); + + // Check if a similar comment has already been posted within the disqualification period + let hasRecentFollowUp = false; + for (const comment of comments.data) { + context.logger.debug("Checking comment for follow-up", { comment }); + if ( + comment && + comment.body === followUpMessage && + comment.user?.type === "Bot" && + now - new Date(comment?.created_at).getTime() <= disqualificationPeriod + ) { + hasRecentFollowUp = true; + break; + } + } + return hasRecentFollowUp; +} diff --git a/src/handlers/wildcard/unassign/check-task-to-unassign.ts b/src/handlers/wildcard/unassign/check-task-to-unassign.ts new file mode 100644 index 000000000..c70d93ca5 --- /dev/null +++ b/src/handlers/wildcard/unassign/check-task-to-unassign.ts @@ -0,0 +1,116 @@ +import { Context } from "../../../types/context"; +import { GitHubAssignEvent, GitHubIssue, GitHubPayload, GitHubUser } from "../../../types/payload"; +import { aggregateAssigneeActivity } from "./aggregate-assignee-activity"; +import { assignEventFound } from "./assign-event-found"; +import { getActiveAssignees } from "./get-active-assignees"; + +export async function checkTaskToUnassign(context: Context, assignedIssue: GitHubIssue) { + const logger = context.logger; + const payload = context.event.payload as GitHubPayload; + const { + timers: { taskDisqualifyDuration, taskFollowUpDuration }, + } = context.config; + + logger.info("Checking for neglected tasks", { issueNumber: assignedIssue.number }); + + if (!assignedIssue.assignees) { + throw logger.error("No assignees found when there are supposed to be assignees.", { + issueNumber: assignedIssue.number, + }); + } + const assignees = assignedIssue.assignees.filter((item): item is GitHubUser => item !== null); + const assigneeLoginsOnly = assignees.map((assignee) => assignee.login); + + const login = payload.repository.owner.login; + const name = payload.repository.name; + const number = assignedIssue.number; + + // DONE: check events - e.g. https://api.github.com/repos/ubiquity/ubiquibot/issues/644/events?per_page=100 + const { assigneeEvents, assigneeCommits } = await aggregateAssigneeActivity({ + context, + login, + name, + number, + assignees: assigneeLoginsOnly, + }); + + // Check if the assignee did any "event activity" or commit within the timeout window + const { activeAssigneesInDisqualifyDuration, activeAssigneesInFollowUpDuration } = getActiveAssignees( + context, + assigneeLoginsOnly, + assigneeEvents, + taskDisqualifyDuration, + assigneeCommits, + taskFollowUpDuration + ); + + // assigneeEvents + const assignEventsOfAssignee: AssignedEvent[] = assigneeEvents.filter( + (event): event is AssignedEvent => event.event === "assigned" && "assignee" in event && "assigner" in event + ); + + const issueAssignEvents = await getAllIssueAssignEvents(context, assignedIssue.number); + const latestAssignEvent = issueAssignEvents[0]; + + logger.debug("Latest assign event", { latestAssignEvent }); + + let disqualifiedAssignees: null | string[] = null; + + if (!latestAssignEvent) { + return logger.debug("No latest assign event found.", { assignEventsOfAssignee }); + } else { + disqualifiedAssignees = await assignEventFound({ + latestAssignEvent, + logger, + assignees, + taskDisqualifyDuration, + disqualifiedAssignees, + context, + activeAssigneesInDisqualifyDuration, + login, + name, + number, + activeAssigneesInFollowUpDuration, + }); + } + return logger.ok("Checked task to unassign", { + issueNumber: assignedIssue.number, + disqualifiedAssignees, + }); +} + +type AssignedEvent = { + id: number; + node_id: string; + url: string; + actor: GitHubUser; + event: "assigned"; + commit_id: string; + commit_url: string; + created_at: string; + assignee: GitHubUser; + assigner: GitHubUser; + performed_via_github_app: null; +}; + +async function getAllIssueAssignEvents(context: Context, issueNumber: number): Promise { + const payload = context.payload; + + try { + const events = (await context.octokit.paginate( + context.octokit.issues.listEvents, + { + owner: payload.repository.owner.login, + repo: payload.repository.name, + issue_number: issueNumber, + per_page: 100, + }, + (response) => response.data.filter((item) => item.event === "assigned") + )) as GitHubAssignEvent[]; + + return events.sort((a, b) => (new Date(a.created_at) > new Date(b.created_at) ? -1 : 1)); + } catch (err: unknown) { + context.logger.fatal("Fetching all issue assign events failed!", err); + return []; + } +} diff --git a/src/handlers/wildcard/unassign/check-tasks-to-unassign.ts b/src/handlers/wildcard/unassign/check-tasks-to-unassign.ts new file mode 100644 index 000000000..d80445c6b --- /dev/null +++ b/src/handlers/wildcard/unassign/check-tasks-to-unassign.ts @@ -0,0 +1,46 @@ +import { Context } from "../../../types/context"; +import { GitHubIssue, IssueType } from "../../../types/payload"; +import { checkTaskToUnassign } from "./check-task-to-unassign"; + +// type Commit[] = Commit[]; // RestEndpointMethodTypes["pulls"]["listCommits"]["response"]["data"]; +export async function checkTasksToUnassign(context: Context) { + const logger = context.logger; + logger.debug("Checking tasks to unassign"); + + const issuesAndPullsOpened = await listAllIssuesAndPullsForRepo(context, IssueType.OPEN); + + // logger.debug("Fetched all issues and pulls opened", { issuesAndPullsOpened }); + const assignedIssues = issuesAndPullsOpened.filter((issue) => issue.assignee); + + const tasksToUnassign = await Promise.all( + assignedIssues.map((assignedIssue: GitHubIssue) => checkTaskToUnassign(context, assignedIssue)) + ); + + logger.debug("Checked tasks to unassign", { tasksToUnassign }); + + logger.ok("Checked all the tasks to unassign", { + tasksToUnassign: tasksToUnassign.filter(Boolean).map((task) => task?.metadata), + }); +} +async function listAllIssuesAndPullsForRepo( + context: Context, + state: "open" | "closed" | "all" = "open", + sort: "created" | "updated" | "comments" = "created", + direction: "desc" | "asc" = "desc" +) { + const payload = context.payload; + try { + const issues = (await context.octokit.paginate(context.octokit.issues.listForRepo, { + owner: payload.repository.owner.login, + repo: payload.repository.name, + state, + sort, + direction, + per_page: 100, + })) as GitHubIssue[]; + return issues; + } catch (err: unknown) { + context.logger.fatal("Listing all issues and pulls failed!", err); + return []; + } +} diff --git a/src/handlers/wildcard/unassign/disqualify-idle-assignees.ts b/src/handlers/wildcard/unassign/disqualify-idle-assignees.ts new file mode 100644 index 000000000..90e992e29 --- /dev/null +++ b/src/handlers/wildcard/unassign/disqualify-idle-assignees.ts @@ -0,0 +1,30 @@ +import { Context } from "../../../types/context"; + +export async function disqualifyIdleAssignees( + context: Context, + { assignees, activeAssigneesInDisqualifyDuration, login, name, number }: DisqualifyIdleAssignees +) { + const idleAssignees = assignees.filter((assignee) => !activeAssigneesInDisqualifyDuration.includes(assignee)); + + if (idleAssignees.length > 0) { + try { + await context.event.octokit.rest.issues.removeAssignees({ + owner: login, + repo: name, + issue_number: number, + assignees: idleAssignees, + }); + context.logger.info("Unassigned idle assignees", { idleAssignees }); + } catch (e: unknown) { + context.logger.error("Failed to unassign idle assignees", e); + } + } + return idleAssignees; +} +interface DisqualifyIdleAssignees { + assignees: string[]; + activeAssigneesInDisqualifyDuration: string[]; + login: string; + name: string; + number: number; +} diff --git a/src/handlers/wildcard/unassign/get-active-assignees-in-disqualify-duration.ts b/src/handlers/wildcard/unassign/get-active-assignees-in-disqualify-duration.ts new file mode 100644 index 000000000..b93c7257c --- /dev/null +++ b/src/handlers/wildcard/unassign/get-active-assignees-in-disqualify-duration.ts @@ -0,0 +1,29 @@ +import { Commit } from "../../../types/commit"; +import { Context } from "../../../types/context"; +import { IssuesListEventsResponseData } from "./unassign"; + +export function getActiveAssigneesInDisqualifyDuration( + context: Context, + assignees: string[], + assigneeEvents: IssuesListEventsResponseData, + taskDisqualifyDuration: number, + assigneeCommits: Commit[] +) { + return assignees.filter(() => { + const currentTime = new Date().getTime(); + const assigneeEventsWithinDuration = assigneeEvents.filter((event) => { + if (!event?.created_at) { + context.logger.debug("Event does not have a created_at property", { event }); + return false; + } + const eventTime = new Date(event?.created_at).getTime(); + return currentTime - eventTime <= taskDisqualifyDuration; + }); + + const assigneeCommitsWithinDuration = assigneeCommits.filter((commit) => { + const date = commit.commit.author?.date || commit.commit.committer?.date || ""; + return date && new Date().getTime() - new Date(date).getTime() <= taskDisqualifyDuration; + }); + return assigneeEventsWithinDuration.length === 0 && assigneeCommitsWithinDuration.length === 0; + }); +} diff --git a/src/handlers/wildcard/unassign/get-active-assignees-in-follow-up-duration.ts b/src/handlers/wildcard/unassign/get-active-assignees-in-follow-up-duration.ts new file mode 100644 index 000000000..2c5a06150 --- /dev/null +++ b/src/handlers/wildcard/unassign/get-active-assignees-in-follow-up-duration.ts @@ -0,0 +1,29 @@ +import { Commit } from "../../../types/commit"; +import { Context } from "../../../types/context"; +import { IssuesListEventsResponseData } from "./unassign"; + +export function getActiveAssigneesInFollowUpDuration( + context: Context, + assignees: string[], + assigneeEvents: IssuesListEventsResponseData, + taskFollowUpDuration: number, + assigneeCommits: Commit[], + taskDisqualifyDuration: number +) { + return assignees.filter(() => { + const currentTime = new Date().getTime(); + const assigneeEventsWithinDuration = assigneeEvents.filter((event) => { + if (!event?.created_at) { + context.logger.debug("Event does not have a created_at property", { event }); + return false; + } + const eventTime = new Date(event?.created_at).getTime(); + return currentTime - eventTime <= taskFollowUpDuration; + }); + const assigneeCommitsWithinDuration = assigneeCommits.filter((commit) => { + const date = commit.commit.author?.date || commit.commit.committer?.date || ""; + return date && new Date().getTime() - new Date(date).getTime() <= taskDisqualifyDuration; + }); + return assigneeEventsWithinDuration.length === 0 && assigneeCommitsWithinDuration.length === 0; + }); +} diff --git a/src/handlers/wildcard/unassign/get-active-assignees.ts b/src/handlers/wildcard/unassign/get-active-assignees.ts new file mode 100644 index 000000000..ef8ea848c --- /dev/null +++ b/src/handlers/wildcard/unassign/get-active-assignees.ts @@ -0,0 +1,36 @@ +import { Commit } from "../../../types/commit"; +import { Context } from "../../../types/context"; +import { getActiveAssigneesInDisqualifyDuration } from "./get-active-assignees-in-disqualify-duration"; +import { getActiveAssigneesInFollowUpDuration } from "./get-active-assignees-in-follow-up-duration"; +import { IssuesListEventsResponseData } from "./unassign"; + +export function getActiveAssignees( + context: Context, + assignees: string[], + assigneeEvents: IssuesListEventsResponseData, + taskDisqualifyDuration: number, + assigneeCommits: Commit[], + taskFollowUpDuration: number +) { + const activeAssigneesInDisqualifyDuration = getActiveAssigneesInDisqualifyDuration( + context, + assignees, + assigneeEvents, + taskDisqualifyDuration, + assigneeCommits + ); + + const activeAssigneesInFollowUpDuration = getActiveAssigneesInFollowUpDuration( + context, + assignees, + assigneeEvents, + taskFollowUpDuration, + assigneeCommits, + taskDisqualifyDuration + ); + + return { + activeAssigneesInDisqualifyDuration, + activeAssigneesInFollowUpDuration, + }; +} diff --git a/src/handlers/wildcard/unassign/get-all-commits-from-pull-request.ts b/src/handlers/wildcard/unassign/get-all-commits-from-pull-request.ts new file mode 100644 index 000000000..93c5587bd --- /dev/null +++ b/src/handlers/wildcard/unassign/get-all-commits-from-pull-request.ts @@ -0,0 +1,23 @@ +import { Commit } from "../../../types/commit"; +import { Context } from "../../../types/context"; + +export async function getAllCommitsFromPullRequest({ context, owner, repo, pullNumber }: GetAllCommits) { + try { + const commits = (await context.octokit.paginate(context.octokit.pulls.listCommits, { + owner, + repo, + pull_number: pullNumber, + per_page: 100, + })) as Commit[]; + return commits; + } catch (err: unknown) { + context.logger.error("Failed to fetch lists of commits", err); + return []; + } +} +interface GetAllCommits { + context: Context; + owner: string; + repo: string; + pullNumber: number; +} diff --git a/src/handlers/wildcard/unassign/get-all-events.ts b/src/handlers/wildcard/unassign/get-all-events.ts new file mode 100644 index 000000000..77e41b976 --- /dev/null +++ b/src/handlers/wildcard/unassign/get-all-events.ts @@ -0,0 +1,29 @@ +import { Context } from "../../../types/context"; +import { isCorrectType } from "./is-correct-type"; +import { IssuesListEventsResponseData } from "./unassign"; + +export async function getAllEvents({ context, owner, repo, issueNumber }: GetAllEvents) { + try { + const events = (await context.octokit.paginate( + context.octokit.rest.issues.listEvents, + { + owner, + repo, + issue_number: issueNumber, + per_page: 100, + }, + (response: { data: any[] }) => + response.data.filter((event) => isCorrectType(event as IssuesListEventsResponseData[0])) + )) as IssuesListEventsResponseData; + return events; + } catch (err: unknown) { + context.logger.error("Failed to fetch lists of events", err); + return []; + } +} +interface GetAllEvents { + context: Context; + owner: string; + repo: string; + issueNumber: number; +} diff --git a/src/handlers/wildcard/unassign/is-correct-type.ts b/src/handlers/wildcard/unassign/is-correct-type.ts new file mode 100644 index 000000000..2221cf725 --- /dev/null +++ b/src/handlers/wildcard/unassign/is-correct-type.ts @@ -0,0 +1,5 @@ +import { IssuesListEventsResponseData } from "./unassign"; + +export function isCorrectType(event: IssuesListEventsResponseData[0]) { + return event && typeof event.id === "number"; +} diff --git a/src/handlers/wildcard/unassign/remind-non-eliminated-assignees.ts b/src/handlers/wildcard/unassign/remind-non-eliminated-assignees.ts new file mode 100644 index 000000000..9a9f7a8b8 --- /dev/null +++ b/src/handlers/wildcard/unassign/remind-non-eliminated-assignees.ts @@ -0,0 +1,58 @@ +import { Context } from "../../../types/context"; +import { checkIfFollowUpAlreadyPosted } from "./check-if-follow-up-already-posted"; + +export async function remindNonEliminatedAssignees( + context: Context, + { + assignees, + disqualifiedAssignees, + activeAssigneesInFollowUpDuration, + login, + name, + number, + taskDisqualifyDuration, + }: FollowUpWithTheRest +) { + const followUpAssignees = assignees.filter( + (assignee) => !disqualifiedAssignees.includes(assignee) && !activeAssigneesInFollowUpDuration.includes(assignee) + ); + + if (followUpAssignees.length > 0) { + const followUpMessage = `@${followUpAssignees.join( + ", @" + )}, this task has been idle for a while. Please provide an update.`; + + // Fetch recent comments + const hasRecentFollowUp = await checkIfFollowUpAlreadyPosted( + context, + login, + name, + number, + followUpMessage, + taskDisqualifyDuration + ); + + if (!hasRecentFollowUp) { + try { + await context.event.octokit.rest.issues.createComment({ + owner: login, + repo: name, + issue_number: number, + body: followUpMessage, + }); + context.logger.info("Followed up with idle assignees", { followUpAssignees }); + } catch (e: unknown) { + context.logger.error("Failed to follow up with idle assignees", e); + } + } + } +} +interface FollowUpWithTheRest { + assignees: string[]; + disqualifiedAssignees: string[]; + activeAssigneesInFollowUpDuration: string[]; + login: string; + name: string; + number: number; + taskDisqualifyDuration: number; +} diff --git a/src/handlers/wildcard/unassign/unassign.ts b/src/handlers/wildcard/unassign/unassign.ts new file mode 100644 index 000000000..0f493c018 --- /dev/null +++ b/src/handlers/wildcard/unassign/unassign.ts @@ -0,0 +1,3 @@ +import { RestEndpointMethodTypes } from "@octokit/rest"; + +export type IssuesListEventsResponseData = RestEndpointMethodTypes["issues"]["listEvents"]["response"]["data"]; diff --git a/src/handlers/wildcard/weekly.ts b/src/handlers/wildcard/weekly.ts deleted file mode 100644 index 8d9dbdc70..000000000 --- a/src/handlers/wildcard/weekly.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { run } from "./weekly/action"; -import { getLastWeeklyTime, updateLastWeeklyTime } from "../../adapters/supabase"; -import { getBotConfig, getBotContext } from "../../bindings"; - -const SEVEN_DAYS = 7 * 24 * 60 * 60 * 1000; // 7 days in milliseconds - -export const checkWeeklyUpdate = async () => { - const { log } = getBotContext(); - const { - mode: { disableAnalytics }, - } = getBotConfig(); - if (disableAnalytics) { - log.info(`Skipping to collect the weekly analytics, reason: mode=${disableAnalytics}`); - return; - } - const curTime = new Date(); - const lastTime = await getLastWeeklyTime(); - if (lastTime == undefined || new Date(lastTime.getTime() + SEVEN_DAYS) < curTime) { - await run(); - await updateLastWeeklyTime(curTime); - } else { - log.info(`Skipping to collect the weekly analytics because 7 days have not passed`); - } -}; diff --git a/src/handlers/wildcard/weekly/action.ts b/src/handlers/wildcard/weekly/action.ts deleted file mode 100644 index 09e06e878..000000000 --- a/src/handlers/wildcard/weekly/action.ts +++ /dev/null @@ -1,360 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -// -// TODO: The above line SHOULD be removed finally by creating types for `any` types -// -import path from "path"; -import axios from "axios"; -import Jimp from "jimp"; -import nodeHtmlToImage from "node-html-to-image"; -import { getBotConfig, getBotContext } from "../../../bindings"; -import { telegramPhotoNotifier } from "../../../adapters"; -import { Context } from "probot"; -import { Payload } from "../../../types"; -import { fetchImage } from "../../../utils/web-assets"; -import { weeklyConfig } from "../../../configs/weekly"; -import { ProximaNovaRegularBase64 } from "../../../assets/fonts/proxima-nova-regular-b64"; -import { ClosedIssueIcon, CommitIcon, MergedPullIcon, OpenedIssueIcon, OpenedPullIcon } from "../../../assets/svgs"; -import { checkRateLimitGit } from "../../../utils"; - -const IMG_PATH = path.resolve(__dirname, "../../../assets/images"); - -const fetchEvents = async (context: Context): Promise => { - const payload = context.payload as Payload; - const dateNow = Date.now(); //mills - const currentDate = new Date(dateNow); - const startTime = `${currentDate.getFullYear()}-${currentDate.getMonth() + 1 < 10 ? `0${currentDate.getMonth() + 1}` : `${currentDate.getMonth() + 1}`}-${ - currentDate.getDate() < 10 ? `0${currentDate.getDate()}` : `${currentDate.getDate()}` - }T00:00:00Z`; - const startTimestamp = new Date(startTime).getTime(); - const endTimestamp = startTimestamp - 604800000; //7 days (seconds/milliseconds * 7) - let shouldFetch = true; - const elemList: any[] = []; - let currentPage = 1; - const perPage = 30; - while (shouldFetch) { - try { - let events; - if (payload.organization) { - events = await context.octokit.activity.listPublicOrgEvents({ - org: payload.organization.login, - per_page: perPage, - page: currentPage, - }); - } else { - events = await context.octokit.activity.listRepoEvents({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - per_page: perPage, - page: currentPage, - }); - } - const pubEvents = events.data; - const headers = events.headers; - - await checkRateLimitGit(headers); - - pubEvents.forEach((elem: any) => { - const elemTimestamp = new Date(elem.created_at as string).getTime(); - if (elemTimestamp <= startTimestamp && elemTimestamp >= endTimestamp) { - //pass - elemList.push(elem); - } else if (elemTimestamp > startTimestamp) { - //outta range - //skip - } else { - //fail end - shouldFetch = false; - } - }); - - currentPage++; - } catch (error) { - shouldFetch = false; - } - } - return elemList; -}; - -type SummaryType = { - commits: number; - openedIssues: number; - closedIssues: number; - openedPRs: number; - mergedPRs: number; -}; - -const processEvents = (JSONList: any[]): SummaryType => { - let openedIssues = 0; - let closedIssues = 0; - let comments = 0; - let bountiesUSD = 0; - let openedPRs = 0; - let closedPRs = 0; - let mergedPRs = 0; - let commits = 0; - JSONList.forEach((elem: any) => { - const { type: eventType } = elem; - switch (eventType) { - case "IssuesEvent": - switch (elem.payload.action) { - case "opened": - openedIssues++; - break; - case "closed": - closedIssues++; - elem.payload.issue?.labels.forEach((elem: any) => { - if (elem.name.includes("Price")) { - const bountyUSD = parseInt( - elem.name - .toString() - .match(/\b\d+\b/) - .join("") - ); - bountiesUSD += bountyUSD; - } - }); - break; - default: - break; - } - break; - case "IssueCommentEvent": - switch (elem.payload.action) { - case "created": - comments++; - break; - default: - break; - } - break; - case "PullRequestEvent": - switch (elem.payload.action) { - case "opened": - openedPRs++; - break; - case "closed": - if (elem.payload.pull_request?.merged === true) { - mergedPRs++; - commits += elem.payload.pull_request?.commits; - } else { - closedPRs++; - } - break; - default: - break; - } - break; - case "PushEvent": - commits += elem.payload.commits?.length; - break; - default: - break; - } - }); - - let summaryInfo: string | SummaryType = - `new issues: ${openedIssues}\n` + - `issues resolved: ${closedIssues}\n` + - `total user interactions count: ${comments}\n` + - `bounties given: ${bountiesUSD} USD\n` + - `new pulls: ${openedPRs}\n` + - `closed pulls: ${closedPRs}\n` + - `merged pulls: ${mergedPRs}\n` + - `total commits: ${commits}\n`; - // @note using it for future reference - - // summaryInfo = - // `📝 commits: ${commits}\n` + - // `📂 issues opened: ${openedIssues}\n` + - // `📁 issues closed: ${closedIssues}\n` + - // `📄 pull requests: ${openedPRs}\n` + - // `📑 pull requests merged: ${mergedPRs}\n`; - - summaryInfo = { - commits, - openedIssues, - closedIssues, - openedPRs, - mergedPRs, - }; - - return summaryInfo; -}; - -const fetchSummary = async (repository: string): Promise => { - const { data } = await axios.post("https://app.whatthediff.ai/api/analyze", { - repository, - }); - const dataPadded = data.review.replace(/<.*?>/gm, ""); - return dataPadded; -}; - -const htmlImage = async (summaryInfo: SummaryType) => { - const wrapElement = (nodeElem: SummaryType) => { - return ` - - - -
          -
          -
          -
          ${CommitIcon}
          -
          Commits
          -
          - ${nodeElem.commits} -
          -
          -
          -
          ${OpenedIssueIcon}
          -
          Issues Opened
          -
          - ${nodeElem.openedIssues} -
          -
          -
          -
          ${ClosedIssueIcon}
          -
          Issues Closed
          -
          - ${nodeElem.closedIssues} -
          -
          -
          -
          ${OpenedPullIcon}
          -
          Pull Requests Opened
          -
          - ${nodeElem.openedPRs} -
          -
          -
          -
          ${MergedPullIcon}
          -
          Pull Requests Merged
          -
          - ${nodeElem.mergedPRs} -
          -
          -
          -
          - - - - `; - }; - - await nodeHtmlToImage({ - output: `${IMG_PATH}/pmg.png`, - html: await wrapElement(summaryInfo), - transparent: true, - puppeteerArgs: { - waitForInitialPage: true, - defaultViewport: { width: 2048, height: 1024 }, - }, - }); -}; - -const getFlatImage = async (): Promise => { - const { - remoteAsset: { - flat: { remoteUrl, isUsing }, - }, - } = weeklyConfig; - let fileName = `${IMG_PATH}/flat.png`; - - if (isUsing) { - try { - await fetchImage(remoteUrl); - fileName = `${IMG_PATH}/webFlat.png`; - } catch (error) { - console.error(`Error reading image. error: ${error}`); - } - } - return fileName; -}; - -const compositeImage = async () => { - const pImage = await Jimp.read(`${IMG_PATH}/pmg.png`); - const fImage = await getFlatImage(); - const image = await Jimp.read(fImage); - image.composite(pImage, 0, 0); - await image.writeAsync(`${IMG_PATH}/fmg.png`); -}; - -const processTelegram = async (caption: string) => { - await telegramPhotoNotifier({ - chatId: "-1000000", //should update with a valid one - file: `${IMG_PATH}/fmg.png`, - caption, - }); -}; - -export const run = async () => { - const context = getBotContext(); - const payload = context.payload as Payload; - const repository = payload.repository.full_name; - const eventsList = await fetchEvents(context); - const summaryInfo = processEvents(eventsList); - const dataPadded = await fetchSummary(repository); - await htmlImage(summaryInfo); - await compositeImage(); - - const { telegram } = getBotConfig(); - if (telegram.token) { - await processTelegram(dataPadded); - } else { - const log = context.log; - log.info("Skipping processTelegram because no token was set."); - } -}; diff --git a/src/handlers/wildcard/weekly/index.ts b/src/handlers/wildcard/weekly/index.ts deleted file mode 100644 index 30697c06e..000000000 --- a/src/handlers/wildcard/weekly/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./action"; diff --git a/src/helpers/comment.ts b/src/helpers/comment.ts deleted file mode 100644 index 7be39376c..000000000 --- a/src/helpers/comment.ts +++ /dev/null @@ -1,140 +0,0 @@ -import Decimal from "decimal.js"; -import { isEmpty } from "lodash"; -import * as parse5 from "parse5"; - -type Node = { - nodeName: string; - tagName?: string; - value?: string; - childNodes?: Node[]; -}; - -const traverse = (result: Record, node: Node, itemsToExclude: string[]): Record => { - if (itemsToExclude.includes(node.nodeName)) { - return result; - } - - if (!result[node.nodeName]) { - result[node.nodeName] = []; - } - - result[node.nodeName].push(node.value?.trim() ?? ""); - - if (node.childNodes && node.childNodes.length > 0) { - node.childNodes.forEach((child) => traverse(result, child, itemsToExclude)); - } - - return result; -}; - -export const parseComments = (comments: string[], itemsToExclude: string[]): Record => { - const result: Record = {}; - - for (const comment of comments) { - const fragment = parse5.parseFragment(comment); - traverse(result, fragment as Node, itemsToExclude); - } - - // remove empty values - if (result["#text"]) { - result["#text"] = result["#text"].filter((str) => str.length > 0); - } - - return result; -}; - -export const generateCollapsibleTable = (data: { element: string; units: number; reward: Decimal }[]) => { - // Check if the data array is empty - if (data.length === 0) { - return "No data to display."; - } - - // Create the table header row - const headerRow = "| element | units | reward |\n| --- | --- | --- |"; - - // Create the table rows from the data array - const tableRows = data.map((item) => `| ${item.element} | ${item.units} | ${item.reward} |`).join("\n"); - - // Create the complete Markdown table - const tableMarkdown = ` -
          - Details - -${headerRow} -${tableRows} - -
          - `; - - return tableMarkdown; -}; - -export const createDetailsTable = ( - amount: string, - paymentURL: string, - username: string, - values: { title: string; subtitle: string; value: string }[], - debug: Record< - string, - { - count: number; - reward: Decimal; - } - > -): string => { - let collapsibleTable = null; - // Generate the table rows based on the values array - const tableRows = values - .map(({ title, value, subtitle }) => { - if (!subtitle || !value) { - return ""; - } - return ` - ${title || ""} - ${subtitle} - ${value} - `; - }) - .join(""); - - if (!isEmpty(debug)) { - const data = Object.entries(debug) - .filter(([_, value]) => value.count > 0) - .map(([key, value]) => { - const element = key === "#text" ? "words" : key; - const units = value.count; - const reward = value.reward; - return { element, units, reward }; - }); - - collapsibleTable = generateCollapsibleTable(data); - } - - // Construct the complete HTML structure - const html = ` -
          - - -

          - [ ${amount} ] -

          -
           @${username}
          -
          -
          - - - ${tableRows} - -
          - ${collapsibleTable ? "COLLAPSIBLE_TABLE_PLACEHOLDER" : ""} -
          - `; - - // Remove spaces and line breaks from the HTML, ignoring the attributes like and [ ... ] - const cleanedHtml = html.replace(/>\s+<").replace(/[\r\n]+/g, ""); - - // Add collapsible table here to avoid compression - const finalHtml = cleanedHtml.replace("COLLAPSIBLE_TABLE_PLACEHOLDER", collapsibleTable || ""); - - return finalHtml; -}; diff --git a/src/helpers/commit.ts b/src/helpers/commit.ts deleted file mode 100644 index 678b4d774..000000000 --- a/src/helpers/commit.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { getBotContext } from "../bindings"; -import { Payload } from "../types"; - -export async function createCommitComment(body: string, commitSha: string, path?: string, owner?: string, repo?: string) { - const context = getBotContext(); - const payload = context.payload as Payload; - if (!owner) { - owner = payload.repository.owner.login; - } - if (!repo) { - repo = payload.repository.name; - } - - await context.octokit.rest.repos.createCommitComment({ - owner: owner, - repo: repo, - commit_sha: commitSha, - body: body, - path: path, - }); -} diff --git a/src/helpers/contracts.ts b/src/helpers/contracts.ts index 28f04e803..6e3c0152a 100644 --- a/src/helpers/contracts.ts +++ b/src/helpers/contracts.ts @@ -1,9 +1,9 @@ import { ethers } from "ethers"; -import { ERC20ABI } from "../configs"; +import { abi as ERC20ABI } from "@openzeppelin/contracts/build/contracts/ERC20.json"; -export const getTokenSymbol = async (tokenAddress: string, rpcUrl: string): Promise => { +export async function getTokenSymbol(tokenAddress: string, rpcUrl: string): Promise { const provider = new ethers.providers.JsonRpcProvider(rpcUrl); const contractInstance = new ethers.Contract(tokenAddress, ERC20ABI, provider); const symbol = await contractInstance.symbol(); return symbol; -}; +} diff --git a/src/helpers/ens.ts b/src/helpers/ens.ts deleted file mode 100644 index a9344c41a..000000000 --- a/src/helpers/ens.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ethers } from "ethers"; -import { getBotConfig } from "../bindings"; - -/** - * Gets the Ethereum address associated with an ENS (Ethereum Name Service) name - * @param ensName - The ENS name, i.e. alice12345.crypto - */ -export const resolveAddress = async (ensName: string): Promise => { - const { - payout: { rpc }, - } = getBotConfig(); - const provider = new ethers.providers.JsonRpcProvider(rpc); - const address = await provider.resolveName(ensName); - return address; -}; diff --git a/src/helpers/file.ts b/src/helpers/file.ts deleted file mode 100644 index b21905098..000000000 --- a/src/helpers/file.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { getBotContext, getLogger } from "../bindings"; - -// Get the previous file content -export async function getPreviousFileContent(owner: string, repo: string, branch: string, filePath: string) { - const logger = getLogger(); - const context = getBotContext(); - - try { - // Get the latest commit of the branch - const branchData = await context.octokit.repos.getBranch({ - owner, - repo, - branch, - }); - const latestCommitSha = branchData.data.commit.sha; - - // Get the commit details - const commitData = await context.octokit.repos.getCommit({ - owner, - repo, - ref: latestCommitSha, - }); - - // Find the file in the commit tree - const file = commitData.data.files ? commitData.data.files.find((file) => file.filename === filePath) : undefined; - if (file) { - // Retrieve the previous file content from the commit's parent - const previousCommitSha = commitData.data.parents[0].sha; - const previousCommit = await context.octokit.git.getCommit({ - owner, - repo, - commit_sha: previousCommitSha, - }); - - // Retrieve the previous file tree - const previousTreeSha = previousCommit.data.tree.sha; - const previousTree = await context.octokit.git.getTree({ - owner, - repo, - tree_sha: previousTreeSha, - recursive: "true", - }); - - // Find the previous file content in the tree - const previousFile = previousTree.data.tree.find((item) => item.path === filePath); - if (previousFile && previousFile.sha) { - // Get the previous file content - const previousFileContent = await context.octokit.git.getBlob({ - owner, - repo, - file_sha: previousFile.sha, - }); - return previousFileContent.data.content; - } - } - return ""; - } catch (error: unknown) { - logger.debug(`Error retrieving previous file content. error: ${error}`); - return ""; - } -} - -export async function getFileContent(owner: string, repo: string, branch: string, filePath: string, commitSha?: string): Promise { - const logger = getLogger(); - const context = getBotContext(); - - try { - if (!commitSha) { - // Get the latest commit of the branch - const branchData = await context.octokit.repos.getBranch({ - owner, - repo, - branch, - }); - commitSha = branchData.data.commit.sha; - } - - // Get the commit details - const commitData = await context.octokit.repos.getCommit({ - owner, - repo, - ref: commitSha, - }); - - // Find the file in the commit tree - const file = commitData.data.files ? commitData.data.files.find((file) => file.filename === filePath) : undefined; - if (file) { - // Retrieve the file tree - const tree = await context.octokit.git.getTree({ - owner, - repo, - tree_sha: commitData.data.commit.tree.sha, - recursive: "true", - }); - - // Find the previous file content in the tree - const file = tree.data.tree.find((item) => item.path === filePath); - if (file && file.sha) { - // Get the previous file content - const fileContent = await context.octokit.git.getBlob({ - owner, - repo, - file_sha: file.sha, - }); - return fileContent.data.content; - } - } - return null; - } catch (error: unknown) { - logger.debug(`Error retrieving previous file content. error: ${error}`); - return null; - } -} diff --git a/src/helpers/get-linked-pull-requests.ts b/src/helpers/get-linked-pull-requests.ts new file mode 100644 index 000000000..c265d81c8 --- /dev/null +++ b/src/helpers/get-linked-pull-requests.ts @@ -0,0 +1,49 @@ +import axios from "axios"; +import { HTMLElement, parse } from "node-html-parser"; +import { GetLinkedParams } from "../handlers/assign/check-pull-requests"; +import { Context } from "../types/context"; +interface GetLinkedResults { + organization: string; + repository: string; + number: number; + href: string; +} +export async function getLinkedPullRequests( + context: Context, + { owner, repository, issue }: GetLinkedParams +): Promise { + const logger = context.logger; + const collection = [] as GetLinkedResults[]; + const { data } = await axios.get(`https://github.com/${owner}/${repository}/issues/${issue}`); + const dom = parse(data); + const devForm = dom.querySelector("[data-target='create-branch.developmentForm']") as HTMLElement; + const linkedList = devForm.querySelectorAll(".my-1"); + if (linkedList.length === 0) { + context.logger.info(`No linked pull requests found`); + return []; + } + + for (const linked of linkedList) { + const relativeHref = linked.querySelector("a")?.attrs?.href; + if (!relativeHref) continue; + const parts = relativeHref.split("/"); + + // check if array size is at least 4 + if (parts.length < 4) continue; + + // extract the organization name and repo name from the link:(e.g. " + const organization = parts[parts.length - 4]; + const repository = parts[parts.length - 3]; + const number = Number(parts[parts.length - 1]); + const href = `https://github.com${relativeHref}`; + + if (`${organization}/${repository}` !== `${owner}/${repository}`) { + logger.info("Skipping linked pull request from another repository", href); + continue; + } + + collection.push({ organization, repository, number, href }); + } + + return collection; +} diff --git a/src/helpers/gpt.ts b/src/helpers/gpt.ts deleted file mode 100644 index 046503d79..000000000 --- a/src/helpers/gpt.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { getBotConfig, getBotContext, getLogger } from "../bindings"; -import { Payload, StreamlinedComment, UserType } from "../types"; -import { getAllIssueComments, getAllLinkedIssuesAndPullsInBody } from "../helpers"; -import OpenAI from "openai"; -import { CreateChatCompletionRequestMessage } from "openai/resources/chat"; -import { ErrorDiff } from "../utils/helpers"; - -export const sysMsg = `You are the UbiquityAI, designed to provide accurate technical answers. \n -Whenever appropriate, format your response using GitHub Flavored Markdown. Utilize tables, lists, and code blocks for clear and organized answers. \n -Do not make up answers. If you are unsure, say so. \n -Original Context exists only to provide you with additional information to the current question, use it to formulate answers. \n -Infer the context of the question from the Original Context using your best judgement. \n -All replies MUST end with "\n\n ".\n -`; - -export const gptContextTemplate = ` -You are the UbiquityAI, designed to review and analyze pull requests. -You have been provided with the spec of the issue and all linked issues or pull requests. -Using this full context, Reply in pure JSON format, with the following structure omitting irrelvant information pertaining to the specification. -You MUST provide the following structure, but you may add additional information if you deem it relevant. -Example:[ - { - "source": "issue #123" - "spec": "This is the issue spec" - "relevant": [ - { - "login": "user", - "body": "This is the relevant context" - "relevancy": "Why is this relevant to the spec?" - }, - { - "login": "other_user", - "body": "This is other relevant context" - "relevancy": "Why is this relevant to the spec?" - } - ] - }, - { - "source": "Pull #456" - "spec": "This is the pull request spec" - "relevant": [ - { - "login": "user", - "body": "This is the relevant context" - "relevancy": "Why is this relevant to the spec?" - }, - { - "login": "other_user", - "body": "This is other relevant context" - "relevancy": "Why is this relevant to the spec?" - } - ] - } -] -`; - -/** - * @notice best used alongside getAllLinkedIssuesAndPullsInBody() in helpers/issue - * @param chatHistory the conversational context to provide to GPT - * @param streamlined an array of comments in the form of { login: string, body: string } - * @param linkedPRStreamlined an array of comments in the form of { login: string, body: string } - * @param linkedIssueStreamlined an array of comments in the form of { login: string, body: string } - */ -export const decideContextGPT = async ( - chatHistory: CreateChatCompletionRequestMessage[], - streamlined: StreamlinedComment[], - linkedPRStreamlined: StreamlinedComment[], - linkedIssueStreamlined: StreamlinedComment[] -) => { - const context = getBotContext(); - const logger = getLogger(); - - const payload = context.payload as Payload; - const issue = payload.issue; - - if (!issue) { - return `Payload issue is undefined`; - } - - // standard comments - const comments = await getAllIssueComments(issue.number); - // raw so we can grab the tag - const commentsRaw = await getAllIssueComments(issue.number, "raw"); - - if (!comments) { - logger.info(`Error getting issue comments`); - return `Error getting issue comments`; - } - - // add the first comment of the issue/pull request - streamlined.push({ - login: issue.user.login, - body: issue.body, - }); - - // add the rest - comments.forEach(async (comment, i) => { - if (comment.user.type == UserType.User || commentsRaw[i].body.includes("")) { - streamlined.push({ - login: comment.user.login, - body: comment.body, - }); - } - }); - - // returns the conversational context from all linked issues and prs - const links = await getAllLinkedIssuesAndPullsInBody(issue.number); - - if (typeof links === "string") { - logger.info(`Error getting linked issues or prs: ${links}`); - return `Error getting linked issues or prs: ${links}`; - } - - linkedIssueStreamlined = links.linkedIssues; - linkedPRStreamlined = links.linkedPrs; - - chatHistory.push( - { - role: "system", - content: "This issue/Pr context: \n" + JSON.stringify(streamlined), - name: "UbiquityAI", - } as CreateChatCompletionRequestMessage, - { - role: "system", - content: "Linked issue(s) context: \n" + JSON.stringify(linkedIssueStreamlined), - name: "UbiquityAI", - } as CreateChatCompletionRequestMessage, - { - role: "system", - content: "Linked Pr(s) context: \n" + JSON.stringify(linkedPRStreamlined), - name: "UbiquityAI", - } as CreateChatCompletionRequestMessage - ); - - // we'll use the first response to determine the context of future calls - const res = await askGPT("", chatHistory); - - return res; -}; - -/** - * @notice base askGPT function - * @param question the question to ask - * @param chatHistory the conversational context to provide to GPT - */ -export const askGPT = async (question: string, chatHistory: CreateChatCompletionRequestMessage[]) => { - const logger = getLogger(); - const config = getBotConfig(); - - if (!config.ask.apiKey) { - logger.info(`No OpenAI API Key provided`); - return ErrorDiff("You must configure the `openai-api-key` property in the bot configuration in order to use AI powered features."); - } - - const openAI = new OpenAI({ - apiKey: config.ask.apiKey, - }); - - const res: OpenAI.Chat.Completions.ChatCompletion = await openAI.chat.completions.create({ - messages: chatHistory, - model: "gpt-3.5-turbo-16k", - max_tokens: config.ask.tokenLimit, - temperature: 0, - }); - - const answer = res.choices[0].message.content; - - const tokenUsage = { - output: res.usage?.completion_tokens, - input: res.usage?.prompt_tokens, - total: res.usage?.total_tokens, - }; - - if (!res) { - logger.info(`No answer found for question: ${question}`); - return `No answer found for question: ${question}`; - } - - return { answer, tokenUsage }; -}; diff --git a/src/helpers/index.ts b/src/helpers/index.ts deleted file mode 100644 index 07cf66d74..000000000 --- a/src/helpers/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -export * from "./shared"; -export * from "./issue"; -export * from "./label"; -export * from "./user"; -export * from "./permit"; -export * from "./ens"; -export * from "./contracts"; -export * from "./comment"; -export * from "./payout"; -export * from "./file"; -export * from "./similarity"; -export * from "./commit"; diff --git a/src/helpers/issue.ts b/src/helpers/issue.ts index 8cd78b047..674a7c547 100644 --- a/src/helpers/issue.ts +++ b/src/helpers/issue.ts @@ -1,852 +1,240 @@ -import { Context } from "probot"; -import { getBotConfig, getBotContext, getLogger } from "../bindings"; -import { AssignEvent, Comment, IssueType, Payload, StreamlinedComment, UserType } from "../types"; -import { checkRateLimitGit } from "../utils"; - -export const getAllIssueEvents = async () => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; - if (!payload.issue) return; - - let shouldFetch = true; - let page_number = 1; - const events = []; - - try { - while (shouldFetch) { - // Fetch issue events - const response = await context.octokit.issues.listEvents({ - owner: payload.repository.owner.login, - repo: payload.repository.full_name, - issue_number: payload.issue.number, - per_page: 100, - page: page_number, - }); - - await checkRateLimitGit(response?.headers); - - if (response?.data?.length > 0) { - events.push(...response.data); - page_number++; - } else { - shouldFetch = false; - } - } - } catch (e: unknown) { - shouldFetch = false; - logger.error(`Getting all issue events failed, reason: ${e}`); - return null; - } - return events; -}; - -export const getAllLabeledEvents = async () => { - const events = await getAllIssueEvents(); - if (!events) return null; - return events.filter((event) => event.event === "labeled"); -}; - -export const clearAllPriceLabelsOnIssue = async (): Promise => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; +import { LogReturn } from "ubiquibot-logger"; +import { Context } from "../types/context"; +import { HandlerReturnValuesNoVoid } from "../types/handlers"; +import { GitHubComment } from "../types/payload"; +export async function clearAllPriceLabelsOnIssue(context: Context) { + const payload = context.payload; if (!payload.issue) return; const labels = payload.issue.labels; - const issuePrices = labels.filter((label) => label.name.toString().startsWith("Price:")); + const issuePrices = labels.filter((label) => label.name.toString().startsWith("Price: ")); if (!issuePrices.length) return; try { - await context.octokit.issues.removeLabel({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - issue_number: payload.issue.number, - name: issuePrices[0].name.toString(), + await context.event.octokit.issues.removeLabel({ + ...context.event.issue(), + name: issuePrices[0].name, }); } catch (e: unknown) { - logger.debug(`Clearing all price labels failed! reason: ${e}`); + context.logger.fatal("Clearing all price labels failed!", e); } -}; +} -export const addLabelToIssue = async (labelName: string) => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; +export async function addLabelToIssue(context: Context, labelName: string) { + const payload = context.payload; if (!payload.issue) { - logger.debug("Issue object is null"); - return; + throw context.logger.fatal("Issue object is null"); } try { await context.octokit.issues.addLabels({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - issue_number: payload.issue.number, + ...context.event.issue(), labels: [labelName], }); } catch (e: unknown) { - logger.debug(`Adding a label to issue failed! reason: ${e}`); + context.logger.fatal("Adding a label to issue failed!", e); } -}; - -export const listIssuesForRepo = async ( - state: "open" | "closed" | "all" = "open", - per_page = 30, - page = 1, - sort: "created" | "updated" | "comments" = "created", - direction: "desc" | "asc" = "desc" -) => { - const context = getBotContext(); - const payload = context.payload as Payload; - - const response = await context.octokit.issues.listForRepo({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - state, - per_page, - page, - sort, - direction, - }); - - await checkRateLimitGit(response.headers); - - if (response.status === 200) { - return response.data; - } else { - return []; - } -}; - -export const listAllIssuesForRepo = async (state: "open" | "closed" | "all" = "open") => { - const issuesArr = []; - let fetchDone = false; - const perPage = 100; - let curPage = 1; - while (!fetchDone) { - const issues = await listIssuesForRepo(state, perPage, curPage); - - // push the objects to array - issuesArr.push(...issues); - - if (issues.length < perPage) fetchDone = true; - else curPage++; - } - - return issuesArr; -}; - -export const addCommentToIssue = async (msg: string, issue_number: number) => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; +} +export async function addCommentToIssue( + context: Context, + message: HandlerReturnValuesNoVoid, + issueNumber: number, + owner?: string, + repo?: string +) { + let comment = message as string; + if (message instanceof LogReturn) { + comment = message.logMessage.diff; + console.trace( + "one of the places that metadata is being serialized as an html comment. this one is unexpected and serves as a fallback" + ); + const metadataSerialized = JSON.stringify(message.metadata); + const metadataSerializedAsComment = ``; + comment = comment.concat(metadataSerializedAsComment); + } + + const payload = context.payload; try { await context.octokit.issues.createComment({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - issue_number, - body: msg, - }); - } catch (e: unknown) { - logger.debug(`Adding a comment failed! reason: ${e}`); - } -}; - -export const updateCommentOfIssue = async (msg: string, issue_number: number, reply_to: Comment) => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; - - try { - const appResponse = await context.octokit.apps.getAuthenticated(); - const { name, slug } = appResponse.data; - logger.info(`App name/slug ${name}/${slug}`); - - const editCommentBy = `${slug}[bot]`; - logger.info(`Bot slug: ${editCommentBy}`); - - const comments = await context.octokit.issues.listComments({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - issue_number: issue_number, - since: reply_to.created_at, - per_page: 30, - }); - - const comment_to_edit = comments.data.find((comment) => { - return comment?.user?.login == editCommentBy && comment.id > reply_to.id; - }); - - if (comment_to_edit) { - logger.info(`For comment_id: ${reply_to.id} found comment_to_edit with id: ${comment_to_edit.id}`); - await context.octokit.issues.updateComment({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - comment_id: comment_to_edit.id, - body: msg, - }); - } else { - logger.info(`Falling back to add comment. Couldn't find response to edit for comment_id: ${reply_to.id}`); - await addCommentToIssue(msg, issue_number); - } - } catch (e: unknown) { - logger.debug(`Updating a comment failed! reason: ${e}`); - } -}; - -export const upsertCommentToIssue = async (issue_number: number, comment: string, action: string, reply_to?: Comment) => { - if (action == "edited" && reply_to) { - await updateCommentOfIssue(comment, issue_number, reply_to); - } else { - await addCommentToIssue(comment, issue_number); - } -}; - -export const upsertLastCommentToIssue = async (issue_number: number, commentBody: string) => { - const logger = getLogger(); - - try { - const comments = await getAllIssueComments(issue_number); - - if (comments.length > 0 && comments[comments.length - 1].body !== commentBody) await addCommentToIssue(commentBody, issue_number); - } catch (e: unknown) { - logger.debug(`Upserting last comment failed! reason: ${e}`); - } -}; - -export const getCommentsOfIssue = async (issue_number: number): Promise => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; - - let result: Comment[] = []; - try { - const response = await context.octokit.rest.issues.listComments({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - issue_number, - }); - - if (response.data) result = response.data as Comment[]; - } catch (e: unknown) { - logger.debug(`Listing issue comments failed! reason: ${e}`); - } - - return result; -}; - -export const getIssueDescription = async (issue_number: number, format: "raw" | "html" | "text" = "raw"): Promise => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; + owner: owner ?? payload.repository.owner.login, + repo: repo ?? payload.repository.name, + issue_number: issueNumber, + body: comment, + }); + } catch (e: unknown) { + context.logger.fatal("Adding a comment failed!", e); + } +} + +// async function upsertLastCommentToIssue(context: Context, issueNumber: number, commentBody: string) { +// try { +// const comments = await getAllIssueComments(context, issueNumber); + +// if (comments.length > 0 && comments[comments.length - 1].body !== commentBody) +// await addCommentToIssue(context, commentBody, issueNumber); +// } catch (e: unknown) { +// context.logger.fatal("Upserting last comment failed!", e); +// } +// } + +// async function getIssueDescription( +// context: Context, +// issueNumber: number, +// format: "raw" | "html" | "text" = "raw" +// ): Promise { +// const payload = context.payload; + +// try { +// const response = await context.octokit.rest.issues.get({ +// owner: payload.repository.owner.login, +// repo: payload.repository.name, +// issue_number: issueNumber, +// mediaType: { +// format, +// }, +// }); + +// let result = response.data.body; + +// if (format === "html") { +// result = response.data.body_html; +// } else if (format === "text") { +// result = response.data.body_text; +// } + +// return result as string; +// } catch (e: unknown) { +// throw context.logger.fatal("Fetching issue description failed!", e); +// } +// } + +export async function getAllIssueComments( + context: Context, + issueNumber: number, + format: "raw" | "html" | "text" | "full" = "raw" +): Promise { + const payload = context.payload; - let result = ""; try { - const response = await context.octokit.rest.issues.get({ + const comments = (await context.octokit.paginate(context.octokit.rest.issues.listComments, { owner: payload.repository.owner.login, repo: payload.repository.name, - issue_number: issue_number, + issue_number: issueNumber, + per_page: 100, mediaType: { format, }, - }); - - await checkRateLimitGit(response?.headers); - switch (format) { - case "raw": - result = response.data.body ?? ""; - break; - case "html": - result = response.data.body_html ?? ""; - break; - case "text": - result = response.data.body_text ?? ""; - break; - } - } catch (e: unknown) { - logger.debug(`Getting issue description failed! reason: ${e}`); - } - return result; -}; - -export const getAllIssueComments = async (issue_number: number, format: "raw" | "html" | "text" | "full" = "raw"): Promise => { - const context = getBotContext(); - const payload = context.payload as Payload; - - const result: Comment[] = []; - let shouldFetch = true; - let page_number = 1; - try { - while (shouldFetch) { - const response = await context.octokit.rest.issues.listComments({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - issue_number: issue_number, - per_page: 100, - page: page_number, - mediaType: { - format, - }, - }); - - await checkRateLimitGit(response?.headers); - - // Fixing infinite loop here, it keeps looping even when its an empty array - if (response?.data?.length > 0) { - response.data.forEach((item) => result?.push(item as Comment)); - page_number++; - } else { - shouldFetch = false; - } - } - } catch (e: unknown) { - shouldFetch = false; - } - - return result; -}; - -export const getAllIssueAssignEvents = async (issue_number: number): Promise => { - const context = getBotContext(); - const payload = context.payload as Payload; - - const result: AssignEvent[] = []; - let shouldFetch = true; - let page_number = 1; - try { - while (shouldFetch) { - const response = await context.octokit.rest.issues.listEvents({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - issue_number: issue_number, - per_page: 100, - page: page_number, - }); - - await checkRateLimitGit(response?.headers); - - // Fixing infinite loop here, it keeps looping even when its an empty array - if (response?.data?.length > 0) { - response.data.filter((item) => item.event === "assigned").forEach((item) => result?.push(item as AssignEvent)); - page_number++; - } else { - shouldFetch = false; - } - } + })) as GitHubComment[]; + return comments; } catch (e: unknown) { - shouldFetch = false; + context.logger.fatal("Fetching all issue comments failed!", e); + return []; } +} - return result.sort((a, b) => (new Date(a.created_at) > new Date(b.created_at) ? -1 : 1)); -}; +export async function isUserAdminOrBillingManager( + context: Context, + username: string +): Promise<"admin" | "billing_manager" | false> { + const payload = context.payload; + const isAdmin = await checkIfIsAdmin(); + if (isAdmin) return "admin"; -export const wasIssueReopened = async (issue_number: number): Promise => { - const context = getBotContext(); - const payload = context.payload as Payload; - - let shouldFetch = true; - let page_number = 1; - try { - while (shouldFetch) { - const response = await context.octokit.rest.issues.listEvents({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - issue_number: issue_number, - per_page: 100, - page: page_number, - }); - - await checkRateLimitGit(response?.headers); - - // Fixing infinite loop here, it keeps looping even when its an empty array - if (response?.data?.length > 0) { - if (response.data.filter((item) => item.event === "reopened").length > 0) return true; - page_number++; - } else { - shouldFetch = false; - } - } - } catch (e: unknown) { - shouldFetch = false; - } + const isBillingManager = await checkIfIsBillingManager(); + if (isBillingManager) return "billing_manager"; return false; -}; - -export const removeAssignees = async (issue_number: number, assignees: string[]): Promise => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; - - try { - await context.octokit.rest.issues.removeAssignees({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - issue_number, - assignees, - }); - } catch (e: unknown) { - logger.debug(`Removing assignees failed! reason: ${e}`); - } -}; - -export const checkUserPermissionForRepoAndOrg = async (username: string, context: Context): Promise => { - const permissionForRepo = await checkUserPermissionForRepo(username, context); - const permissionForOrg = await checkUserPermissionForOrg(username, context); - const userPermission = await getUserPermission(username, context); - - return permissionForOrg || permissionForRepo || userPermission === "admin" || userPermission === "billing_manager"; -}; - -export const checkUserPermissionForRepo = async (username: string, context: Context): Promise => { - const logger = getLogger(); - const payload = context.payload as Payload; - try { - const res = await context.octokit.rest.repos.checkCollaborator({ + async function checkIfIsAdmin() { + const response = await context.octokit.rest.repos.getCollaboratorPermissionLevel({ owner: payload.repository.owner.login, repo: payload.repository.name, username, }); - - return res.status === 204; - } catch (e: unknown) { - logger.error(`Checking if user permisson for repo failed! reason: ${e}`); - return false; + if (response.data.permission === "admin") { + return true; + } else { + return false; + } } -}; -export const checkUserPermissionForOrg = async (username: string, context: Context): Promise => { - const logger = getLogger(); - const payload = context.payload as Payload; - if (!payload.organization) return false; - - try { - await context.octokit.rest.orgs.checkMembershipForUser({ + async function checkIfIsBillingManager() { + if (!payload.organization) throw context.logger.fatal(`No organization found in payload!`); + const { data: membership } = await context.octokit.rest.orgs.getMembershipForUser({ org: payload.organization.login, - username, - }); - // skipping status check due to type error of checkMembershipForUser function of octokit - return true; - } catch (e: unknown) { - logger.error(`Checking if user permisson for org failed! reason: ${e}`); - return false; - } -}; - -export const getUserPermission = async (username: string, context: Context): Promise => { - const logger = getLogger(); - const payload = context.payload as Payload; - - try { - const response = await context.octokit.rest.repos.getCollaboratorPermissionLevel({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - username, + username: payload.repository.owner.login, }); - if (response.status === 200) { - return response.data.permission; + console.trace(membership); + if (membership.role === "billing_manager") { + return true; } else { - return ""; + return false; } - } catch (e: unknown) { - logger.debug(`Checking if user is admin failed! reason: ${e}`); - return ""; } -}; - -export const addAssignees = async (issue_number: number, assignees: string[]): Promise => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; +} +export async function addAssignees(context: Context, issue: number, assignees: string[]) { + const payload = context.payload; try { await context.octokit.rest.issues.addAssignees({ owner: payload.repository.owner.login, repo: payload.repository.name, - issue_number, + issue_number: issue, assignees, }); } catch (e: unknown) { - logger.debug(`Adding assignees failed! reason: ${e}`); - } -}; - -export const deleteLabel = async (label: string): Promise => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; - - try { - const response = await context.octokit.rest.search.issuesAndPullRequests({ - q: `repo:${payload.repository.owner.login}/${payload.repository.name} label:"${label}" state:open`, - }); - if (response.data.items.length === 0) { - //remove label - await context.octokit.rest.issues.deleteLabel({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - name: label, - }); - } - } catch (e: unknown) { - logger.debug(`Label deletion failed! reason: ${e}`); - } -}; - -export const removeLabel = async (name: string) => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; - if (!payload.issue) { - logger.debug("Invalid issue object"); - return; - } - - try { - await context.octokit.issues.removeLabel({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - issue_number: payload.issue.number, - name: name, - }); - } catch (e: unknown) { - logger.debug(`Label removal failed! reason: ${e}`); + context.logger.fatal("Adding assignees failed!", e); } -}; - -export const getAllPullRequests = async (context: Context, state: "open" | "closed" | "all" = "open") => { - const prArr = []; - let fetchDone = false; - const perPage = 100; - let curPage = 1; - while (!fetchDone) { - const prs = await getPullRequests(context, state, perPage, curPage); +} - // push the objects to array - prArr.push(...prs); +export async function getAllPullRequests(context: Context, state: "open" | "closed" | "all" = "open") { + const payload = context.payload; - if (prs.length < perPage) fetchDone = true; - else curPage++; - } - return prArr; -}; -// Use `context.octokit.rest` to get the pull requests for the repository -export const getPullRequests = async (context: Context, state: "open" | "closed" | "all" = "open", per_page: number, page: number) => { - const logger = getLogger(); - const payload = context.payload as Payload; try { - const { data: pulls } = await context.octokit.rest.pulls.list({ + const pulls = await context.octokit.paginate(context.octokit.rest.pulls.list, { owner: payload.repository.owner.login, repo: payload.repository.name, state, - per_page, - page, + per_page: 100, }); return pulls; - } catch (e: unknown) { - logger.debug(`Fetching pull requests failed! reason: ${e}`); + } catch (err: unknown) { + context.logger.fatal("Fetching all pull requests failed!", err); return []; } -}; - -export const closePullRequest = async (pull_number: number) => { - const context = getBotContext(); - const payload = context.payload as Payload; - const logger = getLogger(); - try { - await getBotContext().octokit.rest.pulls.update({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - pull_number, - state: "closed", - }); - } catch (e: unknown) { - logger.debug(`Closing pull requests failed! reason: ${e}`); - } -}; - -export const getAllPullRequestReviews = async (context: Context, pull_number: number, format: "raw" | "html" | "text" | "full" = "raw") => { - const prArr = []; - let fetchDone = false; - const perPage = 30; - let curPage = 1; - while (!fetchDone) { - const prs = await getPullRequestReviews(context, pull_number, perPage, curPage, format); - - // push the objects to array - prArr.push(...prs); - - if (prs.length < perPage) fetchDone = true; - else curPage++; - } - return prArr; -}; - -export const getPullRequestReviews = async ( - context: Context, - pull_number: number, - per_page: number, - page: number, - format: "raw" | "html" | "text" | "full" = "raw" -) => { - const logger = getLogger(); - const payload = context.payload as Payload; - try { - const { data: reviews } = await context.octokit.rest.pulls.listReviews({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - pull_number, - per_page, - page, - mediaType: { - format, - }, - }); - return reviews; - } catch (e: unknown) { - logger.debug(`Fetching pull request reviews failed! reason: ${e}`); - return []; - } -}; - -export const getReviewRequests = async (context: Context, pull_number: number, owner: string, repo: string) => { - const logger = getLogger(); - try { - const response = await context.octokit.pulls.listRequestedReviewers({ - owner: owner, - repo: repo, - pull_number: pull_number, - }); - return response.data; - } catch (e: unknown) { - logger.error(`Error: could not get requested reviewers, reason: ${e}`); - return null; - } -}; -// Get issues by issue number -export const getIssueByNumber = async (context: Context, issue_number: number) => { - const logger = getLogger(); - const payload = context.payload as Payload; - try { - const { data: issue } = await context.octokit.rest.issues.get({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - issue_number, - }); - return issue; - } catch (e: unknown) { - logger.debug(`Fetching issue failed! reason: ${e}`); - return; - } -}; - -export const getPullByNumber = async (context: Context, pull_number: number) => { - const logger = getLogger(); - const payload = context.payload as Payload; - try { - const { data: pull } = await context.octokit.rest.pulls.get({ owner: payload.repository.owner.login, repo: payload.repository.name, pull_number }); - return pull; - } catch (error) { - logger.debug(`Fetching pull failed! reason: ${error}`); - return; - } -}; +} + +// async function getReviewRequests(context: Context, pullNumber: number, owner: string, repo: string) { +// try { +// const response = await context.octokit.pulls.listRequestedReviewers({ +// owner: owner, +// repo: repo, +// pull_number: pullNumber, +// }); +// return response.data; +// } catch (err: unknown) { +// context.logger.fatal("Could not get requested reviewers", err); +// return null; +// } +// } // Get issues assigned to a username -export const getAssignedIssues = async (username: string) => { - const issuesArr = []; - let fetchDone = false; - const perPage = 30; - let curPage = 1; - while (!fetchDone) { - const issues = await listIssuesForRepo(IssueType.OPEN, perPage, curPage); - - // push the objects to array - issuesArr.push(...issues); - - if (issues.length < perPage) fetchDone = true; - else curPage++; - } - - // get only issues assigned to username - const assigned_issues = issuesArr.filter((issue) => !issue.pull_request && issue.assignee && issue.assignee.login === username); - - return assigned_issues; -}; - -export const getOpenedPullRequestsForAnIssue = async (issueNumber: number, userName: string) => { - const pulls = await getOpenedPullRequests(userName); - - return pulls.filter((pull) => { - if (!pull.body) return false; - const issues = pull.body.match(/#(\d+)/gi); - if (!issues) return false; +// async function getOpenedPullRequestsForAnIssue(context: Context, issueNumber: number, userName: string) { +// const pulls = await getOpenedPullRequests(context, userName); - const linkedIssueNumbers = Array.from(new Set(issues.map((issue) => issue.replace("#", "")))); - if (linkedIssueNumbers.indexOf(`${issueNumber}`) !== -1) return true; - return false; - }); -}; +// return pulls.filter((pull) => { +// if (!pull.body) return false; +// const issues = pull.body.match(/#(\d+)/gi); -export const getOpenedPullRequests = async (username: string) => { - const context = getBotContext(); - const prs = await getAllPullRequests(context, "open"); - return prs.filter((pr) => !pr.draft && (pr.user?.login === username || !username)); -}; +// if (!issues) return false; -export const getCommitsOnPullRequest = async (pullNumber: number) => { - const logger = getLogger(); - const context = getBotContext(); - const payload = getBotContext().payload as Payload; - try { - const { data: commits } = await context.octokit.rest.pulls.listCommits({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - pull_number: pullNumber, - }); - return commits; - } catch (e: unknown) { - logger.debug(`Fetching pull request commits failed! reason: ${e}`); - return []; - } -}; - -export const getAvailableOpenedPullRequests = async (username: string) => { - const context = getBotContext(); - const { - unassign: { timeRangeForMaxIssue, timeRangeForMaxIssueEnabled }, - } = await getBotConfig(); - if (!timeRangeForMaxIssueEnabled) return []; - - const opened_prs = await getOpenedPullRequests(username); - - const result = []; - - for (let i = 0; i < opened_prs.length; i++) { - const pr = opened_prs[i]; - const reviews = await getAllPullRequestReviews(context, pr.number); - - if (reviews.length > 0) { - const approvedReviews = reviews.find((review) => review.state === "APPROVED"); - if (approvedReviews) result.push(pr); - } - - if (reviews.length === 0 && (new Date().getTime() - new Date(pr.created_at).getTime()) / (1000 * 60 * 60) >= timeRangeForMaxIssue) { - result.push(pr); - } - } - return result; -}; - -// Strips out all links from the body of an issue or pull request and fetches the conversational context from each linked issue or pull request -export const getAllLinkedIssuesAndPullsInBody = async (issueNumber: number) => { - const context = getBotContext(); - const logger = getLogger(); - - const issue = await getIssueByNumber(context, issueNumber); - - if (!issue) { - return `Failed to fetch using issueNumber: ${issueNumber}`; - } - - if (!issue.body) { - return `No body found for issue: ${issueNumber}`; - } - - const body = issue.body; - const linkedPRStreamlined: StreamlinedComment[] = []; - const linkedIssueStreamlined: StreamlinedComment[] = []; - - const regex = /https:\/\/github\.com\/[^/\s]+\/[^/\s]+\/(issues|pull)\/(\d+)/gi; - const matches = body.match(regex); - - if (matches) { - try { - const linkedIssues: number[] = []; - const linkedPrs: number[] = []; - - // this finds refs via all patterns: #, full url or [#25](url.to.issue) - const issueRef = issue.body.match(/(#(\d+)|https:\/\/github\.com\/[^/\s]+\/[^/\s]+\/(issues|pull)\/(\d+))/gi); - - // if they exist, strip out the # or the url and push them to their arrays - if (issueRef) { - issueRef.forEach((issue) => { - if (issue.includes("#")) { - linkedIssues.push(Number(issue.slice(1))); - } else { - if (issue.split("/")[5] == "pull") { - linkedPrs.push(Number(issue.split("/")[6])); - } else linkedIssues.push(Number(issue.split("/")[6])); - } - }); - } else { - logger.info(`No linked issues or prs found`); - } - - if (linkedPrs.length > 0) { - for (let i = 0; i < linkedPrs.length; i++) { - const pr = await getPullByNumber(context, linkedPrs[i]); - if (pr) { - linkedPRStreamlined.push({ - login: "system", - body: `=============== Pull Request #${pr.number}: ${pr.title} + ===============\n ${pr.body}}`, - }); - const prComments = await getAllIssueComments(linkedPrs[i]); - const prCommentsRaw = await getAllIssueComments(linkedPrs[i], "raw"); - prComments.forEach(async (comment, i) => { - if (comment.user.type == UserType.User || prCommentsRaw[i].body.includes("")) { - linkedPRStreamlined.push({ - login: comment.user.login, - body: comment.body, - }); - } - }); - } - } - } - - if (linkedIssues.length > 0) { - for (let i = 0; i < linkedIssues.length; i++) { - const issue = await getIssueByNumber(context, linkedIssues[i]); - if (issue) { - linkedIssueStreamlined.push({ - login: "system", - body: `=============== Issue #${issue.number}: ${issue.title} + ===============\n ${issue.body} `, - }); - const issueComments = await getAllIssueComments(linkedIssues[i]); - const issueCommentsRaw = await getAllIssueComments(linkedIssues[i], "raw"); - issueComments.forEach(async (comment, i) => { - if (comment.user.type == UserType.User || issueCommentsRaw[i].body.includes("")) { - linkedIssueStreamlined.push({ - login: comment.user.login, - body: comment.body, - }); - } - }); - } - } - } - - return { - linkedIssues: linkedIssueStreamlined, - linkedPrs: linkedPRStreamlined, - }; - } catch (error) { - logger.info(`Error getting linked issues or prs: ${error}`); - return `Error getting linked issues or prs: ${error}`; - } - } else { - logger.info(`No matches found`); - return { - linkedIssues: [], - linkedPrs: [], - }; - } -}; +// const linkedIssueNumbers = Array.from(new Set(issues.map((issue) => issue.replace("#", "")))); +// if (linkedIssueNumbers.indexOf(`${issueNumber}`) !== -1) return true; +// return false; +// }); +// } diff --git a/src/helpers/label.ts b/src/helpers/label.ts index 7bc3744ec..69af46233 100644 --- a/src/helpers/label.ts +++ b/src/helpers/label.ts @@ -1,127 +1,38 @@ -import { Context } from "probot"; -import { getBotConfig, getBotContext, getLogger } from "../bindings"; -import { calculateBountyPrice } from "../handlers"; -import { Label, Payload } from "../types"; -import { deleteLabel } from "./issue"; -import { calculateWeight } from "../helpers"; +import { Context } from "../types/context"; +import { Label } from "../types/label"; +import { GitHubPayload } from "../types/payload"; // cspell:disable -export const COLORS = { - default: "ededed", - price: "1f883d", -}; +const COLORS = { default: "ededed", price: "1f883d" }; // cspell:enable -export const listLabelsForRepo = async (per_page?: number, page?: number): Promise => { - const context = getBotContext(); - const payload = context.payload as Payload; +export async function listLabelsForRepo(context: Context): Promise { + const payload = context.event.payload as GitHubPayload; - const res = await context.octokit.rest.issues.listLabelsForRepo({ + const res = await context.event.octokit.rest.issues.listLabelsForRepo({ owner: payload.repository.owner.login, repo: payload.repository.name, - per_page: per_page ?? 100, - page: page ?? 1, + per_page: 100, + page: 1, }); if (res.status === 200) { return res.data; } - throw new Error(`Failed to fetch lists of labels, code: ${res.status}`); -}; + throw context.logger.fatal("Failed to fetch lists of labels", { status: res.status }); +} -export const createLabel = async (name: string, labelType?: keyof typeof COLORS): Promise => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; - try { - await context.octokit.rest.issues.createLabel({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - name, - color: COLORS[labelType ?? "default"], - }); - } catch (err: unknown) { - logger.debug(`Error creating a label: ${name}. Is it already there?`); - } -}; - -export const getLabel = async (name: string): Promise => { - const context = getBotContext(); - const logger = getLogger(); - const payload = context.payload as Payload; - try { - const res = await context.octokit.rest.issues.getLabel({ - owner: payload.repository.owner.login, - repo: payload.repository.name, - name, - }); - return res.status === 200 ? true : false; - } catch (err: unknown) { - logger.debug(`Error creating a label: ${name}. Is it already there?`); - } - - return false; -}; - -// Function to update labels based on the base rate difference -export const updateLabelsFromBaseRate = async (owner: string, repo: string, context: Context, labels: Label[], previousBaseRate: number) => { - const logger = getLogger(); - const config = getBotConfig(); - - const newLabels: string[] = []; - const previousLabels: string[] = []; - - for (const timeLabel of config.price.timeLabels) { - for (const priorityLabel of config.price.priorityLabels) { - const targetPrice = calculateBountyPrice(calculateWeight(timeLabel), calculateWeight(priorityLabel), config.price.baseMultiplier); - const targetPriceLabel = `Price: ${targetPrice} USD`; - newLabels.push(targetPriceLabel); - - const previousTargetPrice = calculateBountyPrice(calculateWeight(timeLabel), calculateWeight(priorityLabel), previousBaseRate); - const previousTargetPriceLabel = `Price: ${previousTargetPrice} USD`; - previousLabels.push(previousTargetPriceLabel); - } - } - - const uniqueNewLabels = [...new Set(newLabels)]; - const uniquePreviousLabels = [...new Set(previousLabels)]; - - const labelsFiltered: string[] = labels.map((obj) => obj["name"]); - const usedLabels = uniquePreviousLabels.filter((value: string) => labelsFiltered.includes(value)); - - logger.debug(`${usedLabels.length} previous labels used on issues`); - - try { - for (const label of usedLabels) { - if (label.startsWith("Price: ")) { - const labelData = labels.find((obj) => obj["name"] === label) as Label; - const index = uniquePreviousLabels.findIndex((obj) => obj === label); - - const exist = await getLabel(uniqueNewLabels[index]); - if (exist) { - // we have to delete first - logger.debug(`Deleted ${uniqueNewLabels[index]}, updating it`); - await deleteLabel(uniqueNewLabels[index]); - } - - // we can update safely - await context.octokit.issues.updateLabel({ - owner, - repo, - name: label, - new_name: uniqueNewLabels[index], - color: labelData.color, - description: labelData.description, - headers: { - "X-GitHub-Api-Version": "2022-11-28", - }, - }); - - logger.debug(`Label updated: ${label} -> ${uniqueNewLabels[index]}`); - } - } - } catch (error: unknown) { - logger.error(`Error updating labels, error: ${error}`); - } -}; +export async function createLabel( + context: Context, + name: string, + labelType = "default" as keyof typeof COLORS +): Promise { + const payload = context.event.payload as GitHubPayload; + await context.event.octokit.rest.issues.createLabel({ + owner: payload.repository.owner.login, + repo: payload.repository.name, + name, + color: COLORS[labelType], + }); +} diff --git a/src/helpers/parser.ts b/src/helpers/parser.ts deleted file mode 100644 index 42821a5b5..000000000 --- a/src/helpers/parser.ts +++ /dev/null @@ -1,93 +0,0 @@ -import axios from "axios"; -import { HTMLElement, parse } from "node-html-parser"; -import { getPullByNumber } from "./issue"; -import { getBotContext, getLogger } from "../bindings"; - -interface GitParser { - owner: string; - repo: string; - issue_number?: number; - pull_number?: number; -} - -export interface LinkedPR { - prOrganization: string; - prRepository: string; - prNumber: number; - prHref: string; -} - -export const gitLinkedIssueParser = async ({ owner, repo, pull_number }: GitParser) => { - const logger = getLogger(); - try { - const { data } = await axios.get(`https://github.com/${owner}/${repo}/pull/${pull_number}`); - const dom = parse(data); - const devForm = dom.querySelector("[data-target='create-branch.developmentForm']") as HTMLElement; - const linkedIssues = devForm.querySelectorAll(".my-1"); - - if (linkedIssues.length === 0) { - return null; - } - - const issueUrl = linkedIssues[0].querySelector("a")?.attrs?.href || ""; - return issueUrl; - } catch (error) { - logger.error(`${JSON.stringify(error)}`); - return null; - } -}; - -export const gitLinkedPrParser = async ({ owner, repo, issue_number }: GitParser): Promise => { - const logger = getLogger(); - try { - const prData = []; - const { data } = await axios.get(`https://github.com/${owner}/${repo}/issues/${issue_number}`); - const dom = parse(data); - const devForm = dom.querySelector("[data-target='create-branch.developmentForm']") as HTMLElement; - const linkedPRs = devForm.querySelectorAll(".my-1"); - if (linkedPRs.length === 0) return []; - - for (const linkedPr of linkedPRs) { - const prUrl = linkedPr.querySelector("a")?.attrs?.href; - - if (!prUrl) continue; - - const parts = prUrl.split("/"); - - // check if array size is at least 4 - if (parts.length < 4) continue; - - // extract the organization name and repo name from the link:(e.g. " - const prOrganization = parts[parts.length - 4]; - const prRepository = parts[parts.length - 3]; - const prNumber = Number(parts[parts.length - 1]); - const prHref = `https://github.com${prUrl}`; - - if (`${prOrganization}/${prRepository}` !== `${owner}/${repo}`) continue; - - prData.push({ prOrganization, prRepository, prNumber, prHref }); - } - - return prData; - } catch (error) { - logger.error(`${JSON.stringify(error)}`); - return []; - } -}; - -export const getLatestPullRequest = async (prs: LinkedPR[]) => { - const context = getBotContext(); - let linkedPullRequest = null; - for (const _pr of prs) { - if (Number.isNaN(_pr.prNumber)) return null; - const pr = await getPullByNumber(context, _pr.prNumber); - if (!pr || !pr.merged) continue; - - if (!linkedPullRequest) linkedPullRequest = pr; - else if (linkedPullRequest.merged_at && pr.merged_at && new Date(linkedPullRequest.merged_at) < new Date(pr.merged_at)) { - linkedPullRequest = pr; - } - } - - return linkedPullRequest; -}; diff --git a/src/helpers/payout.ts b/src/helpers/payout.ts index c6f4a06f2..e40baf047 100644 --- a/src/helpers/payout.ts +++ b/src/helpers/payout.ts @@ -11,12 +11,6 @@ * 2. Gelato network should support the added payment token (https://docs.gelato.network/developer-services/relay/api#oracles-chainid-paymenttokens) */ -import { Static } from "@sinclair/typebox"; -import { PayoutConfigSchema } from "../types"; -import { getUserPermission } from "./issue"; -import { getBotContext, getLogger } from "../bindings"; -import { getAccessLevel } from "../adapters/supabase"; - // available tokens for payouts const PAYMENT_TOKEN_PER_NETWORK: Record = { "1": { @@ -29,46 +23,14 @@ const PAYMENT_TOKEN_PER_NETWORK: Record }, }; -type PayoutConfigPartial = Omit, "networkId" | "privateKey" | "permitBaseUrl">; - -/** - * Returns payout config for a particular network - * @param networkId network id - * @returns RPC URL and payment token - */ -export const getPayoutConfigByNetworkId = (networkId: number): PayoutConfigPartial => { - const paymentToken = PAYMENT_TOKEN_PER_NETWORK[networkId.toString()]; +export function getPayoutConfigByNetworkId(evmNetworkId: number) { + const paymentToken = PAYMENT_TOKEN_PER_NETWORK[evmNetworkId.toString()]; if (!paymentToken) { - throw new Error(`No config setup for networkId: ${networkId}`); + throw new Error(`No config setup for evmNetworkId: ${evmNetworkId}`); } return { rpc: paymentToken.rpc, paymentToken: paymentToken.token, }; -}; - -export const hasLabelEditPermission = async (label: string, caller: string, repository: string) => { - const context = getBotContext(); - const logger = getLogger(); - const permissionLevel = await getUserPermission(caller, context); - - // get text before : - const match = label.split(":"); - if (match.length == 0) return false; - const label_type = match[0].toLowerCase(); - - if (permissionLevel !== "admin" && permissionLevel !== "billing_manager") { - // check permission - const accessible = await getAccessLevel(caller, repository, label_type); - - if (accessible) { - return true; - } - - logger.info(`@${caller} is not allowed to edit label ${label}`); - return false; - } - - return true; -}; +} diff --git a/src/helpers/permit.ts b/src/helpers/permit.ts deleted file mode 100644 index deddcffe0..000000000 --- a/src/helpers/permit.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { MaxUint256, PermitTransferFrom, SignatureTransfer } from "@uniswap/permit2-sdk"; -import { BigNumber, ethers } from "ethers"; -import { getBotConfig, getBotContext, getLogger } from "../bindings"; -import { keccak256, toUtf8Bytes } from "ethers/lib/utils"; -import Decimal from "decimal.js"; -import { Payload } from "../types"; -import { savePermit } from "../adapters/supabase"; - -const PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3"; // same on all networks - -export type Permit = { - id: number; - createdAt: Date; - organizationId: number | null; - repositoryId: number; - issueId: number; - networkId: number; - bountyHunterId: number; - bountyHunterAddress: string; - tokenAddress: string; - payoutAmount: string; - nonce: string; - deadline: string; - signature: string; - walletOwnerAddress: string; -}; - -export type InsertPermit = Omit; - -type TxData = { - permit: { - permitted: { - token: string; - amount: string; - }; - nonce: string; - deadline: string; - }; - transferDetails: { - to: string; - requestedAmount: string; - }; - owner: string; - signature: string; -}; - -/** - * Generates permit2 signature data with `spender` and `amountInETH` - * - * @param spender The recipient address we're going to send tokens - * @param amountInETH The token amount in ETH - * - * @returns Permit2 url including base64 encoded data - */ -export const generatePermit2Signature = async ( - spender: string, - amountInEth: Decimal, - identifier: string, - userId = "" -): Promise<{ txData: TxData; payoutUrl: string }> => { - const { - payout: { networkId, privateKey, permitBaseUrl, rpc, paymentToken }, - } = getBotConfig(); - const logger = getLogger(); - const provider = new ethers.providers.JsonRpcProvider(rpc); - const adminWallet = new ethers.Wallet(privateKey, provider); - - const permitTransferFromData: PermitTransferFrom = { - permitted: { - // token we are permitting to be transferred - token: paymentToken, - // amount we are permitting to be transferred - amount: ethers.utils.parseUnits(amountInEth.toString(), 18), - }, - // who can transfer the tokens - spender: spender, - nonce: BigNumber.from(keccak256(toUtf8Bytes(identifier + userId))), - // signature deadline - deadline: MaxUint256, - }; - - const { domain, types, values } = SignatureTransfer.getPermitData(permitTransferFromData, PERMIT2_ADDRESS, networkId); - - const signature = await adminWallet._signTypedData(domain, types, values); - const txData: TxData = { - permit: { - permitted: { - token: permitTransferFromData.permitted.token, - amount: permitTransferFromData.permitted.amount.toString(), - }, - nonce: permitTransferFromData.nonce.toString(), - deadline: permitTransferFromData.deadline.toString(), - }, - transferDetails: { - to: permitTransferFromData.spender, - requestedAmount: permitTransferFromData.permitted.amount.toString(), - }, - owner: adminWallet.address, - signature: signature, - }; - - const base64encodedTxData = Buffer.from(JSON.stringify(txData)).toString("base64"); - - const payoutUrl = `${permitBaseUrl}?claim=${base64encodedTxData}&network=${networkId}`; - logger.info(`Generated permit2 url: ${payoutUrl}`); - return { txData, payoutUrl }; -}; - -export const savePermitToDB = async (bountyHunterId: number, txData: TxData): Promise => { - const logger = getLogger(); - - const context = getBotContext(); - const payload = context.payload as Payload; - const issue = payload.issue; - const repository = payload.repository; - const organization = payload.organization; - if (!issue || !repository) { - logger.error("Cannot save permit to DB, missing issue, repository or organization"); - throw new Error("Cannot save permit to DB, missing issue, repository or organization"); - } - - const { payout } = getBotConfig(); - const { networkId } = payout; - - const permit: InsertPermit = { - organizationId: organization?.id ?? null, - repositoryId: repository?.id, - issueId: issue?.id, - networkId: networkId, - bountyHunterId: bountyHunterId, - tokenAddress: txData.permit.permitted.token, - payoutAmount: txData.permit.permitted.amount, - bountyHunterAddress: txData.transferDetails.to, - nonce: txData.permit.nonce, - deadline: txData.permit.deadline, - signature: txData.signature, - walletOwnerAddress: txData.owner, - }; - - const savedPermit = await savePermit(permit); - logger.info(`Saved permit to DB: ${JSON.stringify(savedPermit)}`); - return savedPermit; -}; diff --git a/src/helpers/shared.ts b/src/helpers/shared.ts index 86e1599eb..650342f01 100644 --- a/src/helpers/shared.ts +++ b/src/helpers/shared.ts @@ -1,46 +1,52 @@ import ms from "ms"; -import { getBotContext } from "../bindings"; -import { LabelItem, Payload, UserType } from "../types"; + +import { Context as ProbotContext } from "probot"; +import { Label } from "../types/label"; +import { GitHubPayload, UserType } from "../types/payload"; const contextNamesToSkip = ["workflow_run"]; -export const shouldSkip = (): { skip: boolean; reason: string } => { - const context = getBotContext(); - const { name } = context; - const payload = context.payload as Payload; - const res: { skip: boolean; reason: string } = { skip: false, reason: "" }; - if (contextNamesToSkip.includes(name)) { - res.skip = true; - res.reason = `excluded context name: ${name}`; +export function shouldSkip(context: ProbotContext) { + const payload = context.payload as GitHubPayload; + const response = { stop: false, reason: null } as { stop: boolean; reason: string | null }; + + if (contextNamesToSkip.includes(context.name)) { + response.stop = true; + response.reason = `excluded context name: "${context.name}"`; } else if (payload.sender.type === UserType.Bot) { - res.skip = true; - res.reason = "sender is a bot"; + response.stop = true; + response.reason = "sender is a bot"; } - return res; -}; -export const wait = (ms: number) => new Promise((r) => setTimeout(r, ms)); + return response; +} -export const calculateWeight = (label: LabelItem | undefined): number => { - if (!label) return 0; - const matches = label.name.match(/\d+/); +export function calculateLabelValue(label: string): number { + const matches = label.match(/\d+/); const number = matches && matches.length > 0 ? parseInt(matches[0]) || 0 : 0; - if (label.name.toLowerCase().includes("priority")) return number; - if (label.name.toLowerCase().includes("minute")) return number * 0.002; - if (label.name.toLowerCase().includes("hour")) return number * 0.125; - if (label.name.toLowerCase().includes("day")) return 1 + (number - 1) * 0.25; - if (label.name.toLowerCase().includes("week")) return number + 1; - if (label.name.toLowerCase().includes("month")) return 5 + (number - 1) * 8; + if (label.toLowerCase().includes("priority")) return number; + // throw new Error(`Label ${label} is not a priority label`); + if (label.toLowerCase().includes("minute")) return number * 0.002; + if (label.toLowerCase().includes("hour")) return number * 0.125; + if (label.toLowerCase().includes("day")) return 1 + (number - 1) * 0.25; + if (label.toLowerCase().includes("week")) return number + 1; + if (label.toLowerCase().includes("month")) return 5 + (number - 1) * 8; return 0; -}; +} -export const calculateDuration = (label: LabelItem): number => { - if (!label) return 0; - if (label.name.toLowerCase().includes("priority")) return 0; +export function calculateDurations(labels: Label[]): number[] { + // from shortest to longest + const durations: number[] = []; - const pattern = /<(\d+\s\w+)/; - const result = label.name.match(pattern); - if (!result) return 0; + labels.forEach((label: Label) => { + const matches = label.name.match(/<(\d+)\s*(\w+)/); + if (matches && matches.length >= 3) { + const number = parseInt(matches[1]); + const unit = matches[2]; + const duration = ms(`${number} ${unit}`) / 1000; + durations.push(duration); + } + }); - return ms(result[1]) / 1000; -}; + return durations.sort((a, b) => a - b); +} diff --git a/src/helpers/similarity.ts b/src/helpers/similarity.ts deleted file mode 100644 index a5743e562..000000000 --- a/src/helpers/similarity.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { getLogger } from "../bindings"; -import axios, { AxiosError } from "axios"; -import { ajv } from "../utils"; -import { Static, Type } from "@sinclair/typebox"; -import { backOff } from "exponential-backoff"; -import { Issue } from "../types"; - -export const extractImportantWords = async (issue: Issue): Promise => { - const res = await getAnswerFromChatGPT( - "", - `${ - process.env.CHATGPT_USER_PROMPT_FOR_IMPORTANT_WORDS || - "I need your help to find important words (e.g. unique adjectives) from github issue below and I want to parse them easily so please separate them using #(No other contexts needed). Please separate the words by # so I can parse them easily. Please answer simply as I only need the important words. Here is the issue content.\n" - } '${`Issue title: ${issue.title}\nIssue content: ${issue.body}`}'`, - parseFloat(process.env.IMPORTANT_WORDS_AI_TEMPERATURE || "0") - ); - if (res === "") return []; - return res.split(/[,# ]/); -}; - -export const measureSimilarity = async (first: Issue, second: Issue): Promise => { - const res = await getAnswerFromChatGPT( - "", - `${( - process.env.CHATGPT_USER_PROMPT_FOR_MEASURE_SIMILARITY || - 'I have two github issues and I need to measure the possibility of the 2 issues are the same content (I need to parse the % so other contents are not needed and give me only the number in %).\n Give me in number format and add % after the number.\nDo not tell other things since I only need the number (e.g. 85%). Here are two issues:\n 1. "%first%"\n2. "%second%"' - ) - .replace("%first%", `Issue title: ${first.title}\nIssue content: ${first.body}`) - .replace("%second%", `Issue title: ${second.title}\nIssue content: ${second.body}`)}`, - parseFloat(process.env.MEASURE_SIMILARITY_AI_TEMPERATURE || "0") - ); - const matches = res.match(/\d+/); - const percent = matches && matches.length > 0 ? parseInt(matches[0]) || 0 : 0; - return percent; -}; - -const ChatMessageSchema = Type.Object({ - content: Type.String(), -}); - -const ChoiceSchema = Type.Object({ - message: ChatMessageSchema, -}); - -const ChoicesSchema = Type.Object({ - choices: Type.Array(ChoiceSchema), -}); - -type Choices = Static; - -export const getAnswerFromChatGPT = async (systemPrompt: string, userPrompt: string, temperature = 0, max_tokens = 1500): Promise => { - const logger = getLogger(); - const body = JSON.stringify({ - model: "gpt-3.5-turbo", - messages: [ - { - role: "system", - content: systemPrompt, - }, - { - role: "user", - content: userPrompt, - }, - ], - max_tokens, - temperature, - stream: false, - }); - const config = { - method: "post", - url: `${process.env.OPENAI_API_HOST || "https://api.openai.com"}/v1/chat/completions`, - headers: { - Authorization: `Bearer ${process.env.OPENAI_API_KEY}`, - "Content-Type": "application/json", - }, - data: body, - }; - try { - const response = await backOff(() => axios(config), { - startingDelay: 6000, - retry: (e: AxiosError) => { - if (e.response && e.response.status === 429) return true; - return false; - }, - }); - const data: Choices = response.data; - const validate = ajv.compile(ChoicesSchema); - const valid = validate(data); - if (!valid) { - logger.error(`Error occured from OpenAI`); - return ""; - } - const { choices: choice } = data; - if (choice.length <= 0) { - logger.error(`No result from OpenAI`); - return ""; - } - const answer = choice[0].message.content; - return answer; - } catch (error) { - logger.error(`Getting response from ChatGPT failed: ${error}`); - return ""; - } -}; diff --git a/src/helpers/user.ts b/src/helpers/user.ts deleted file mode 100644 index 5f151f241..000000000 --- a/src/helpers/user.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { getBotContext, getLogger } from "../bindings"; -import { User } from "../types"; - -/** - * @dev Gets the publicly available information about `username` - * - * @param username The username you're getting information for - */ -export const getUser = async (username: string): Promise => { - const context = getBotContext(); - const logger = getLogger(); - - try { - const res = await context.octokit.rest.users.getByUsername({ - username, - }); - - if (res.status === 200) return res.data as User; - else { - logger.debug(`Unsatisfied response { status: ${res.status}, data: ${res.data}`); - } - } catch (err: unknown) { - logger.info(`Getting user info failed! err: ${err}`); - } - - return undefined; -}; - -/** - * @dev Gets organization membership of a user - * @param orgname The organization name - * @param username The user name - * - * @returns The role name of a user in the organization. "admin" || "member" || "billing_manager" - */ -export const getOrgMembershipOfUser = async (org: string, username: string): Promise => { - const context = getBotContext(); - const logger = getLogger(); - let membership: string | undefined = undefined; - - try { - const res = await context.octokit.rest.orgs.getMembershipForUser({ - org, - username, - }); - - if (res.status === 200) { - membership = res.data.role; - } else { - logger.debug(`Unsatisfied response { status: ${res.status}, data: ${res.data}`); - } - } catch (err: unknown) { - logger.info(`Getting organization membership failed! err: ${err}`); - } - - return membership; -}; diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 2028d5c27..000000000 --- a/src/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Probot } from "probot"; -import { EmitterWebhookEventName } from "@octokit/webhooks"; -import { bindEvents } from "./bindings"; -import { GithubEvent } from "./types"; - -const UBIQUITY = ` - _| _| _|_|_| _|_|_| _|_| _| _| _|_|_| _|_|_|_|_| _| _| - _| _| _| _| _| _| _| _| _| _| _| _| _| - _| _| _|_|_| _| _| _|_| _| _| _| _| _| - _| _| _| _| _| _| _| _| _| _| _| _| - _|_| _|_|_| _|_|_| _|_| _| _|_| _|_|_| _| _| - - `; - -export default function main(app: Probot) { - console.log(UBIQUITY); - const allowedEvents = Object.values(GithubEvent) as EmitterWebhookEventName[]; - app.on(allowedEvents, bindEvents); -} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 000000000..f7ab9f4c2 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,13 @@ +import sourceMapSupport from "source-map-support"; +sourceMapSupport.install(); + +import { Probot } from "probot"; +import { bindEvents } from "./bindings/event"; +import { GitHubEvent } from "./types/github-events"; + +export default function main(app: Probot) { + const allowedEvents = Object.values(GitHubEvent); + app.on(allowedEvents, async (context) => { + await bindEvents(context); + }); +} diff --git a/src/tests/after-all-handler.ts b/src/tests/after-all-handler.ts new file mode 100644 index 000000000..4dc6135b8 --- /dev/null +++ b/src/tests/after-all-handler.ts @@ -0,0 +1,7 @@ +import { getServer } from "./commands-test"; + +export function afterAllHandler(): () => Promise { + return async () => { + await getServer().stop(); + }; +} diff --git a/src/tests/before-all-handler.ts b/src/tests/before-all-handler.ts new file mode 100644 index 000000000..11e27fa34 --- /dev/null +++ b/src/tests/before-all-handler.ts @@ -0,0 +1,105 @@ +import { Probot, run } from "probot"; + +import { bindEvents } from "../bindings/event"; +import { GitHubEvent } from "../types/github-events"; +import { + customOctokit, + getAdminUser, + getAdminUsername, + getCollaboratorUser, + getCollaboratorUsername, + owner, + repo, + setAdminUser, + setAdminUsername, + setCollaboratorUser, + setCollaboratorUsername, + setServer, +} from "./commands-test"; +import { waitForNWebhooks, webhookEventEmitter } from "./utils"; + +export function beforeAllHandler(): jest.ProvidesHookCallback { + return async () => { + const adminPAT = process.env.TEST_ADMIN_PAT; + if (!adminPAT) { + throw new Error("missing TEST_ADMIN_PAT"); + } + + setAdminUser(new customOctokit({ auth: adminPAT })); + + const { data } = await getAdminUser().rest.users.getAuthenticated(); + setAdminUsername(data.login); + + // check if the user is admin + const adminUsername = getAdminUsername(); + if (!adminUsername) { + throw new Error("TEST_ADMIN_PAT is not admin"); + } + + const { data: data1 } = await getAdminUser().rest.repos.getCollaboratorPermissionLevel({ + repo, + owner, + username: adminUsername, + }); + if (data1.permission !== "admin") { + throw new Error("TEST_ADMIN_PAT is not admin"); + } + + const outsideCollaboratorPAT = process.env.TEST_OUTSIDE_COLLABORATOR_PAT; + if (!outsideCollaboratorPAT) { + throw new Error("missing TEST_OUTSIDE_COLLABORATOR_PAT"); + } + + setCollaboratorUser(new customOctokit({ auth: outsideCollaboratorPAT })); + + const { data: data2 } = await getCollaboratorUser().rest.users.getAuthenticated(); + setCollaboratorUsername(data2.login); + + // check if the user is outside collaborator + const collaboratorUsername = getCollaboratorUsername(); + if (!collaboratorUsername) { + throw new Error("TEST_OUTSIDE_COLLABORATOR_PAT is not outside collaborator"); + } + const { data: data3 } = await getAdminUser().rest.repos.getCollaboratorPermissionLevel({ + repo, + owner, + username: collaboratorUsername, + }); + if (data3.permission === "admin" || data3.permission === "write") { + throw new Error("TEST_OUTSIDE_COLLABORATOR_PAT is not outside collaborator"); + } + if (data3.permission !== "read") { + throw new Error("TEST_OUTSIDE_COLLABORATOR_PAT does not have read access"); + } + + const server = await run((app: Probot) => { + const allowedEvents = Object.values(GitHubEvent) as GitHubEvent[]; + app.on(allowedEvents, async (context) => { + await bindEvents(context); + webhookEventEmitter.emit("event", context.payload); + }); + }); + + setServer(server); + + // FIXME: this is a hack to get around the fact that the config is not being updated + // build errors were happening because the config was not being updated + + // await updateConfig({ + // octokit: getAdminUser(), + // owner, + // repo: "ubiquibot-config", + // path: ".github/ubiquibot-config.yml", + // config: {}, //orgConfig, + // }); + // await waitForNWebhooks(1); + // await updateConfig({ + // octokit: getAdminUser(), + // owner, + // repo: "ubiquibot-config", + // path: ".github/ubiquibot-config.yml", + // config: {}, //repoConfig, + // }); + await waitForNWebhooks(1); + }; +} diff --git a/src/tests/commands-test.ts b/src/tests/commands-test.ts new file mode 100644 index 000000000..ac72630c7 --- /dev/null +++ b/src/tests/commands-test.ts @@ -0,0 +1,70 @@ +import { describe } from "@jest/globals"; +import "dotenv/config"; +import { Octokit } from "octokit"; +import { Server } from "probot"; +import { COMMIT_HASH } from "../commit-hash"; +import { afterAllHandler } from "./after-all-handler"; +import { beforeAllHandler } from "./before-all-handler"; +import { testSuite } from "./test-suite"; + +export const TEST_TIME_LABEL = "Time: <1 Hour"; +export const TEST_PRIORITY_LABEL = "Priority: 1 (Normal)"; + +export const SIX_HOURS = 6 * 60 * 60 * 1000; // 6 hours + +// return the current 7 character git commit hash using git rev-parse +export const GIT_COMMIT_HASH = COMMIT_HASH?.substring(0, 7) ?? null; + +export const owner = process.env.TEST_ORGANIZATION_NAME || "ubiquibot"; +export const repo = process.env.TEST_REPOSITORY_NAME || "staging"; + +// generate setters and getters for the following variables +let octokitAdmin: Octokit; +let octokitCollaborator: Octokit; +let adminUsername: string | null = null; +let collaboratorUsername: string | null = null; +let server: Server; + +export function getAdminUser(): Octokit { + return octokitAdmin; +} +export function setAdminUser(value: Octokit) { + octokitAdmin = value; +} +export function getCollaboratorUser(): Octokit { + return octokitCollaborator; +} +export function setCollaboratorUser(value: Octokit) { + octokitCollaborator = value; +} +export function getAdminUsername(): string | null { + return adminUsername; +} +export function setAdminUsername(value: string) { + adminUsername = value; +} +export function getCollaboratorUsername(): string | null { + return collaboratorUsername; +} +export function setCollaboratorUsername(value: string) { + collaboratorUsername = value; +} +export function getServer(): Server { + return server; +} +export function setServer(value: Server) { + server = value; +} + +export const customOctokit = Octokit.defaults({ + throttle: { + onRateLimit: () => true, + onSecondaryRateLimit: () => true, + }, +}); + +beforeAll(beforeAllHandler(), SIX_HOURS); + +afterAll(afterAllHandler(), SIX_HOURS); + +describe("commands test", testSuite()); diff --git a/src/tests/message-test.ts b/src/tests/message-test.ts deleted file mode 100644 index 97aec52a8..000000000 --- a/src/tests/message-test.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { telegramFormattedNotifier, telegramNotifier } from "../adapters/telegram/helpers"; -const chatIds = ["tg1", "tg2", "tg3"]; // SHOULD update chatIds with valid ones - -export async function messageTests() { - /**@method telegramNotifier - call unformatted issue */ - await telegramNotifier({ - chatIds: chatIds, - action: `new issue`, - title: `Optimize CI/CD Build Speed`, - description: `I worked through getting the build process to work by force \nmoving all dev dependencies into dependencies, but \nnow the build process is extremely slow on vercel.`, - id: `10`, - ref: `https://github.com/ubiquity/ubiquity-dollar/issues/10`, - user: `pavlovcik`, - }); - - /**@method telegramNotifier - call unformatted pull */ - await telegramNotifier({ - chatIds: chatIds, - action: `new pull`, - title: `Enhancement/styles`, - description: `Small enhancements but mostly renamed the \ninternal smart contract references, and \nadded support for DAI and USDT in the inventory.`, - id: `246`, - ref: `https://github.com/ubiquity/ubiquity-dollar/pull/246`, - user: `pavlovcik`, - }); - - /**@method telegramFormattedNotifier - call formatted issue */ - await telegramFormattedNotifier({ - chatIds: chatIds, - text: - `new issue: Optimize CI/CD Build Speed ` + - `#10 ` + - `@` + - `pavlovcik\n` + - `I worked through getting the build process to work by force \nmoving all dev dependencies into dependencies, but \nnow the build process is extremely slow on vercel.`, - parseMode: "HTML", - }); - - /**@method telegramFormattedNotifier - call formatted pull */ - await telegramFormattedNotifier({ - chatIds: chatIds, - text: - `new pull: Enhancement/styles ` + - `#246 ` + - `@` + - `pavlovcik\n` + - `Small enhancements but mostly renamed the \ninternal smart contract references, and \nadded support for DAI and USDT in the inventory.`, - parseMode: "HTML", - }); -} diff --git a/src/tests/summarize-test.ts b/src/tests/summarize-test.ts deleted file mode 100644 index 621548a8c..000000000 --- a/src/tests/summarize-test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { run } from "../handlers/wildcard/weekly/action"; - -run() - .then((res) => { - console.log(res); - }) - .catch((err) => { - console.log(err); - }); diff --git a/src/tests/test-repo-config.ts b/src/tests/test-repo-config.ts new file mode 100644 index 000000000..8b333629a --- /dev/null +++ b/src/tests/test-repo-config.ts @@ -0,0 +1,63 @@ +export const configuration = { + evmNetworkId: 100, + basePriceMultiplier: 1, + issueCreatorMultiplier: 1, + timeLabels: [ + { name: "Time: <1 Hour" }, + { name: "Time: <2 Hours" }, + { name: "Time: <4 Hours" }, + { name: "Time: <1 Day" }, + { name: "Time: <1 Week" }, + ], + priorityLabels: [ + { name: "Priority: 1 (Normal)" }, + { name: "Priority: 2 (Medium)" }, + { name: "Priority: 3 (High)" }, + { name: "Priority: 4 (Urgent)" }, + { name: "Priority: 5 (Emergency)" }, + ], + defaultLabels: ["Time: <1 Hour", "Priority: 1 (Normal)"], + maxPermitPrice: 1000, + maxConcurrentTasks: 5, + promotionComment: null, + assistivePricing: true, + registerWalletWithVerification: false, + commandSettings: [ + { name: "start", enabled: true }, + { name: "stop", enabled: true }, + { name: "wallet", enabled: true }, + { name: "multiplier", enabled: true }, + { name: "query", enabled: true }, + { name: "autopay", enabled: true }, + { name: "labels", enabled: true }, + { name: "help", enabled: true }, + { name: "payout", enabled: true }, + ], + publicAccessControl: { + setLabel: true, + fundExternalClosedIssue: true, + }, + incentives: { + comment: { + elements: { + code: 5, + img: 5, + h1: 1, + li: 0.5, + a: 0.5, + blockquote: 0, + }, + totals: { + word: 0.1, + }, + }, + }, + taskStaleTimeoutDuration: "15 minutes", + + newContributorGreeting: { + enabled: true, + header: "Welcome to the test sandbox! My Header!", + helpMenu: true, + footer: "Please note that this is a footer from a bot. Thanks!", + }, +}; diff --git a/src/tests/test-suite.ts b/src/tests/test-suite.ts new file mode 100644 index 000000000..6248fe826 --- /dev/null +++ b/src/tests/test-suite.ts @@ -0,0 +1,506 @@ +import { expect, test } from "@jest/globals"; +import { GitHubIssue } from "../types/payload"; +import { + // getCollaboratorUsername, + getAdminUser, + // TEST_PRIORITY_LABEL, + // TEST_TIME_LABEL, + getAdminUsername, + GIT_COMMIT_HASH, + owner, + repo, + SIX_HOURS, +} from "./commands-test"; +import checkLastComment, { + createComment, + // createLabel, + getLastComment, + // removeLabelFromIssue, + waitForNWebhooks, +} from "./utils"; + +let issue: GitHubIssue; + +export function testSuite(): () => void { + beforeAll(createAndAlwaysUseThisTestIssue(), SIX_HOURS); + + return allTests(); +} + +function createAndAlwaysUseThisTestIssue(): jest.ProvidesHookCallback { + return async () => { + const res = await getAdminUser().rest.issues.create({ + repo, + owner, + title: `${GIT_COMMIT_HASH} - E2E TEST`, + }); + issue = res.data as GitHubIssue; + + await waitForNWebhooks(4); + }; +} + +function allTests(): () => void { + return () => { + test( + "/wallet correct address", + async () => { + const newWallet = "0x82AcFE58e0a6bE7100874831aBC56Ee13e2149e7"; + await createComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + body: `/wallet ${newWallet}`, + }); + await waitForNWebhooks(2); + await checkLastComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + expectedComment: `Updated the wallet address for @${getAdminUsername()} successfully!\t Your new address: \`${newWallet}\``, + }); + }, + SIX_HOURS + ); + + test( + "/wallet wrong address", + async () => { + const newWallet = "0x82AcFE58e0a6bE7100874831aBC56"; + await createComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + body: `/wallet ${newWallet}`, + }); + await waitForNWebhooks(2); + await checkLastComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + expectedComment: `Please include your wallet or ENS address.\n usage: /wallet 0x0000000000000000000000000000000000000000`, + }); + }, + SIX_HOURS + ); + + test( + "/multiplier", + async () => { + await createComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + body: `/multiplier @${getAdminUsername()}`, + }); + await waitForNWebhooks(2); + + await checkLastComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + expectedComment: `Successfully changed the payout multiplier for @${getAdminUsername()} to 1. The reason is not provided.`, + }); + + await createComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + body: `/multiplier @${getAdminUsername()} 2`, + }); + await waitForNWebhooks(2); + + await checkLastComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + expectedComment: `Successfully changed the payout multiplier for @${getAdminUsername()} to 2. The reason is not provided. This feature is designed to limit the contributor's compensation for any task on the current repository due to other compensation structures (i.e. salary.) are you sure you want to use a price multiplier above 1?`, + }); + + await createComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + body: `/multiplier @${getAdminUsername()} 2 "Testing reason"`, + }); + await waitForNWebhooks(2); + + await checkLastComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + expectedComment: `Successfully changed the payout multiplier for @${getAdminUsername()} to 2. The reason provided is "Testing reason". This feature is designed to limit the contributor's compensation for any task on the current repository due to other compensation structures (i.e. salary.) are you sure you want to use a price multiplier above 1?`, + }); + + await createComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + body: `/multiplier @${getAdminUsername()} abcd`, + }); + await waitForNWebhooks(2); + + await checkLastComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + expectedComment: `Successfully changed the payout multiplier for @${getAdminUsername()} to 1. The reason provided is "abcd".`, + }); + + await createComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + body: `/multiplier abcd`, + }); + await waitForNWebhooks(2); + + await checkLastComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + expectedComment: `Successfully changed the payout multiplier for @${getAdminUsername()} to 1. The reason provided is "abcd".`, + }); + }, + SIX_HOURS + ); + + test( + "/query", + async () => { + const newWallet = "0x82AcFE58e0a6bE7100874831aBC56Ee13e2149e7"; + await createComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + body: `/wallet ${newWallet}`, + }); + await waitForNWebhooks(2); + + const multiplier = "5"; + await createComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + body: `/multiplier @${getAdminUsername()} ${multiplier} 'Testing'`, + }); + await waitForNWebhooks(2); + + await createComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + body: `/query @${getAdminUsername()}`, + }); + await waitForNWebhooks(2); + + const lastComment = await getLastComment({ octokit: getAdminUser(), owner, repo, issueNumber: issue.number }); + expect(lastComment.body).toContain( + `@${getAdminUsername()}'s wallet address is ${newWallet}, multiplier is ${multiplier}` + ); + }, + SIX_HOURS + ); + + test( + "/query wrong username", + async () => { + await createComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + body: `/query @INVALID_$USERNAME`, + }); + await waitForNWebhooks(2); + + await checkLastComment({ + octokit: getAdminUser(), + owner, + repo, + issueNumber: issue.number, + expectedComment: `Invalid syntax for query command \n usage /query @user`, + }); + }, + SIX_HOURS + ); + + test( + "/help", + async () => { + await createComment({ octokit: getAdminUser(), owner, repo, issueNumber: issue.number, body: `/help` }); + await waitForNWebhooks(2); + + const lastComment = await getLastComment({ octokit: getAdminUser(), owner, repo, issueNumber: issue.number }); + expect(lastComment.body?.includes("Available Commands")).toBe(true); + }, + SIX_HOURS + ); + + // test( + // "/labels", + // async () => { + // await createLabel(getAdminUser(), owner, repo, TEST_PRIORITY_LABEL); + + // await getAdminUser().rest.issues.update({ + // owner, + // repo, + // issue_number: issue.number, + // labels: [], + // }); + + // await createComment(getAdminUser(), owner, repo, issue.number, `/labels set-priority @${getCollaboratorUsername()} false`); + // await waitForNWebhooks(2); + + // let lastComment = await getLastComment(getAdminUser(), owner, repo, issue.number); + // expect(lastComment.body).toContain(`Updated access for @${getCollaboratorUsername()} successfully!\t Access: **priority** for "${owner}/${repo}"`); + + // // collaborator adds label + // await addLabelToIssue(getCollaboratorUser(), owner, repo, issue.number, TEST_PRIORITY_LABEL); + // await waitForNWebhooks(3); + + // let issueDetails = await getAdminUser().rest.issues.get({ + // owner, + // repo, + // issue_number: issue.number, + // }); + // expect(issueDetails.data.labels?.length).toBe(0); + + // lastComment = await getLastComment(getAdminUser(), owner, repo, issue.number); + // expect(lastComment.body).toContain(`@${getCollaboratorUsername()}, You are not allowed to add Priority: 1 (Normal)`); + + // await getAdminUser().rest.issues.update({ + // owner, + // repo, + // issue_number: issue.number, + // labels: [TEST_PRIORITY_LABEL], + // }); + + // await removeLabelFromIssue(getCollaboratorUser(), owner, repo, issue.number, TEST_PRIORITY_LABEL); + // await waitForNWebhooks(3); + + // issueDetails = await getAdminUser().rest.issues.get({ + // owner, + // repo, + // issue_number: issue.number, + // }); + // expect(issueDetails.data.labels?.length).toBe(1); + + // lastComment = await getLastComment(getAdminUser(), owner, repo, issue.number); + // expect(lastComment.body).toContain(`@${getCollaboratorUsername()}, You are not allowed to remove Priority: 1 (Normal)`); + + // await createComment(getAdminUser(), owner, repo, issue.number, `/labels set-priority @${getCollaboratorUsername()} true`); + // await waitForNWebhooks(2); + + // lastComment = await getLastComment(getAdminUser(), owner, repo, issue.number); + // expect(lastComment.body).toContain(`Updated access for @${getCollaboratorUsername()} successfully!\t Access: **priority** for "${owner}/${repo}"`); + + // await removeLabelFromIssue(getCollaboratorUser(), owner, repo, issue.number, TEST_PRIORITY_LABEL); + // await waitForNWebhooks(1); + + // issueDetails = await getAdminUser().rest.issues.get({ + // owner, + // repo, + // issue_number: issue.number, + // }); + // expect(issueDetails.data.labels?.length).toBe(0); + + // await addLabelToIssue(getCollaboratorUser(), owner, repo, issue.number, TEST_PRIORITY_LABEL); + // await waitForNWebhooks(1); + + // issueDetails = await getAdminUser().rest.issues.get({ + // owner, + // repo, + // issue_number: issue.number, + // }); + // expect(issueDetails.data.labels?.length).toBe(1); + // }, + // SIX_HOURS + // ); + + // test( + // "/start and /stop", + // async () => { + // await getAdminUser().rest.issues.update({ + // owner, + // repo, + // issue_number: issue.number, + // labels: [], + // }); + + // await getAdminUser().rest.issues.update({ + // owner, + // repo, + // issue_number: issue.number, + // state: "closed", + // }); + // await waitForNWebhooks(2); + + // let lastComment = await getLastComment(getAdminUser(), owner, repo, issue.number); + // expect(lastComment.body).toContain("Permit generation disabled because this issue didn't qualify for funding"); + + // await getAdminUser().rest.issues.update({ + // owner, + // repo, + // issue_number: issue.number, + // state: "open", + // }); + // await waitForNWebhooks(1); + + // try { + // await getAdminUser().rest.issues.createLabel({ + // owner, + // repo, + // name: TEST_TIME_LABEL, + // }); + // } catch (err) { + // expect(err).toBeDefined(); + // } finally { + // await getAdminUser().rest.issues.addLabels({ + // owner, + // repo, + // issue_number: issue.number, + // labels: [TEST_TIME_LABEL], + // }); + // await waitForNWebhooks(1); + // } + + // try { + // await getAdminUser().rest.issues.createLabel({ + // owner, + // repo, + // name: TEST_PRIORITY_LABEL, + // }); + // } catch (err) { + // expect(err).toBeDefined(); + // } finally { + // await getAdminUser().rest.issues.addLabels({ + // owner, + // repo, + // issue_number: issue.number, + // labels: [TEST_PRIORITY_LABEL], + // }); + // await waitForNWebhooks(2); + // } + + // await getAdminUser().rest.issues.update({ + // owner, + // repo, + // issue_number: issue.number, + // state: "closed", + // }); + // await waitForNWebhooks(2); + + // lastComment = await getLastComment(getAdminUser(), owner, repo, issue.number); + // expect(lastComment.body).toContain("Permit generation disabled because assignee is undefined"); + + // await getAdminUser().rest.issues.update({ + // owner, + // repo, + // issue_number: issue.number, + // state: "open", + // }); + // await waitForNWebhooks(1); + + // await createComment(getAdminUser(), owner, repo, issue.number, `/autopay false`); + // await waitForNWebhooks(2); + + // lastComment = await getLastComment(getAdminUser(), owner, repo, issue.number); + // expect(lastComment.body).toContain("Automatic payment for this issue is enabled: **false**"); + + // await createComment(getAdminUser(), owner, repo, issue.number, '/start'); + // await waitForNWebhooks(3); + + // lastComment = await getLastComment(getAdminUser(), owner, repo, issue.number); + // const lastCommentBody = lastComment.body?.toLowerCase(); + // expect(lastCommentBody).toContain("deadline"); + // expect(lastCommentBody).toContain("registered wallet"); + // expect(lastCommentBody).toContain("payment multiplier"); + // expect(lastCommentBody).toContain("multiplier reason"); + + // await createComment(getAdminUser(), owner, repo, issue.number, `/stop`); + // await waitForNWebhooks(3); + + // lastComment = await getLastComment(getAdminUser(), owner, repo, issue.number); + // expect(lastComment.body).toBe(`You have been unassigned from the task @${getAdminUsername()}`); + + // await createComment(getAdminUser(), owner, repo, issue.number, '/start'); + // await waitForNWebhooks(3); + + // await getAdminUser().rest.issues.update({ + // owner, + // repo, + // issue_number: issue.number, + // state: "closed", + // }); + // await waitForNWebhooks(2); + + // lastComment = await getLastComment(getAdminUser(), owner, repo, issue.number); + // expect(lastComment.body).toContain("Permit generation disabled because automatic payment for this issue is disabled."); + + // await getAdminUser().rest.issues.update({ + // owner, + // repo, + // issue_number: issue.number, + // state: "open", + // }); + // await waitForNWebhooks(1); + + // await createComment(getAdminUser(), owner, repo, issue.number, `/autopay true`); + // await waitForNWebhooks(2); + + // lastComment = await getLastComment(getAdminUser(), owner, repo, issue.number); + // expect(lastComment.body).toBe("Automatic payment for this issue is enabled: **true**"); + + // await getAdminUser().rest.issues.update({ + // owner, + // repo, + // issue_number: issue.number, + // state: "closed", + // state_reason: "not_planned", + // }); + // await waitForNWebhooks(2); + + // lastComment = await getLastComment(getAdminUser(), owner, repo, issue.number); + // expect(lastComment.body).toContain("Permit generation disabled because this is marked as unplanned"); + + // await getAdminUser().rest.issues.update({ + // owner, + // repo, + // issue_number: issue.number, + // state: "open", + // }); + // await waitForNWebhooks(1); + + // await getAdminUser().rest.issues.update({ + // owner, + // repo, + // issue_number: issue.number, + // state: "closed", + // }); + // await waitForNWebhooks(2); + + // lastComment = await getLastComment(getAdminUser(), owner, repo, issue.number); + // expect(lastComment.body).toContain("Task Assignee Reward"); + // }, + // SIX_HOURS + // ); + }; +} diff --git a/src/tests/utils.ts b/src/tests/utils.ts new file mode 100644 index 000000000..1e8eb62fb --- /dev/null +++ b/src/tests/utils.ts @@ -0,0 +1,181 @@ +import { expect } from "@jest/globals"; +import { RequestError } from "@octokit/request-error"; +import EventEmitter from "events"; +import { Octokit } from "octokit"; +import YAML from "yaml"; +import { BotConfig } from "../types/configuration-types"; + +export const webhookEventEmitter = new EventEmitter(); + +export function waitForNWebhooks(n = 1) { + return new Promise((resolve, reject) => { + let i = 0; + + const timer = setTimeout(() => { + reject(new Error(`timeout, received ${i} webhooks, expected ${n}`)); + }, 30000); + + webhookEventEmitter.on("event", () => { + i += 1; + if (i == n) { + clearTimeout(timer); + setTimeout(resolve, 1000); + } + }); + }); +} + +export async function createLabel({ octokit, owner, repo, label, color }: CreateLabel) { + try { + await octokit.rest.issues.createLabel({ + owner, + repo, + name: label, + color, + }); + } catch (err: unknown) { + if (err instanceof RequestError) { + expect(err).toBeDefined(); + expect(err?.status).toBe(422); + } + } +} + +export async function addLabelToIssue({ octokit, owner, repo, issueNumber, label }: LabelParams) { + await octokit.rest.issues.addLabels({ + owner, + repo, + issue_number: issueNumber, + labels: [label], + }); +} + +export async function removeLabelFromIssue({ octokit, owner, repo, issueNumber, label }: LabelParams) { + await octokit.rest.issues.removeLabel({ + owner, + repo, + issue_number: issueNumber, + name: label, + }); +} +export async function createAndAddLabel({ octokit, owner, repo, issueNumber, label }: LabelParams) { + try { + await octokit.rest.issues.createLabel({ + owner, + repo, + name: label, + }); + } catch (err: unknown) { + if (err instanceof RequestError) { + expect(err).toBeDefined(); + expect(err?.status).toBe(422); + } + } finally { + await octokit.rest.issues.addLabels({ + owner, + repo, + issue_number: issueNumber, + labels: [label], + }); + await waitForNWebhooks(1); + } +} + +export async function updateConfig({ octokit, owner, repo, path, config }: UpdateConfig) { + let sha: string | undefined = undefined; + try { + const fileContent = await octokit.rest.repos.getContent({ + owner, + repo, + path, + }); + if (Array.isArray(fileContent.data)) { + throw new Error("ubiquibot-config.yml should not be directory"); + } + if (fileContent.data.type !== "file") { + throw new Error("ubiquibot-config.yml is not a file"); + } + sha = fileContent.data.sha; + } catch (err: unknown) { + if (err instanceof RequestError) { + expect(err).toBeDefined(); + expect(err?.status).toBe(404); + } + } + + await octokit.rest.repos.createOrUpdateFileContents({ + owner, + repo, + path, + message: "test(e2e): automated update config for test", + content: Buffer.from(YAML.stringify(config)).toString("base64"), + sha, + }); +} + +export async function createComment({ octokit, owner, repo, issueNumber, body }: CreateComment) { + await octokit.rest.issues.createComment({ + repo, + owner, + issue_number: issueNumber, + body: body, + }); +} +interface GetLastComment { + octokit: Octokit; + owner: string; + repo: string; + issueNumber: number; +} +export async function getLastComment({ octokit, owner, repo, issueNumber }: GetLastComment) { + const { data } = await octokit.rest.issues.listComments({ + repo, + owner, + issue_number: issueNumber, + per_page: 100, + }); + expect(data.length).toBeGreaterThan(0); + return data[data.length - 1]; +} + +export default async function checkLastComment({ + octokit, + owner, + repo, + issueNumber, + expectedComment, +}: CheckLastComment) { + const lastComment = await getLastComment({ octokit, owner, repo, issueNumber }); + expect(lastComment.body).toBe(expectedComment); +} + +interface OctokitParams { + octokit: Octokit; + owner: string; + repo: string; +} + +interface IssueParams extends OctokitParams { + issueNumber: number; +} + +interface LabelParams extends IssueParams { + label: string; +} + +interface CreateLabel extends LabelParams { + color?: string; +} + +interface UpdateConfig extends OctokitParams { + path: string; + config: BotConfig; +} + +interface CreateComment extends IssueParams { + body: string; +} + +interface CheckLastComment extends IssueParams { + expectedComment: string; +} diff --git a/src/types/adapters.ts b/src/types/adapters.ts deleted file mode 100644 index 8bf68b4e0..000000000 --- a/src/types/adapters.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { SupabaseClient } from "@supabase/supabase-js"; -import { Telegram as TelegramClient } from "telegraf"; - -export type Adapters = { - supabase: SupabaseClient; - telegram: TelegramClient; -}; diff --git a/src/types/commit.ts b/src/types/commit.ts new file mode 100644 index 000000000..87f97fe1c --- /dev/null +++ b/src/types/commit.ts @@ -0,0 +1,79 @@ +export interface Commit { + sha: string; + node_id: string; + commit: { + author: { + name: string; + email: string; + date: string; + }; + committer: { + name: string; + email: string; + date: string; + }; + message: string; + tree: { + sha: string; + url: string; + }; + url: string; + comment_count: number; + verification: { + verified: boolean; + reason: string; + signature: string; + payload: string; + }; + }; + url: string; + html_url: string; + comments_url: string; + author: { + login: string; + id: number; + node_id: string; + avatar_url: string; + gravatar_id: string; + url: string; + html_url: string; + followers_url: string; + following_url: string; + gists_url: string; + starred_url: string; + subscriptions_url: string; + organizations_url: string; + repos_url: string; + events_url: string; + received_events_url: string; + type: string; + site_admin: boolean; + }; + committer: { + login: string; + id: number; + node_id: string; + avatar_url: string; + gravatar_id: string; + url: string; + html_url: string; + followers_url: string; + following_url: string; + gists_url: string; + starred_url: string; + subscriptions_url: string; + organizations_url: string; + repos_url: string; + events_url: string; + received_events_url: string; + type: string; + site_admin: boolean; + }; + parents: [ + { + sha: string; + url: string; + html_url: string; + } + ]; +} diff --git a/src/types/config.ts b/src/types/config.ts deleted file mode 100644 index a22683a28..000000000 --- a/src/types/config.ts +++ /dev/null @@ -1,247 +0,0 @@ -import { Static, Type } from "@sinclair/typebox"; -import { LogLevel } from "./log"; - -const LabelItemSchema = Type.Object( - { - name: Type.String(), - }, - { - additionalProperties: false, - } -); -export type LabelItem = Static; - -const CommentIncentivesSchema = Type.Object( - { - elements: Type.Record(Type.String(), Type.Number()), - totals: Type.Object( - { - word: Type.Number(), - }, - { additionalProperties: false } - ), - }, - { additionalProperties: false } -); -export type CommentIncentives = Static; - -const IncentivesSchema = Type.Object( - { - comment: CommentIncentivesSchema, - }, - { additionalProperties: false } -); - -export type Incentives = Static; - -const CommandItemSchema = Type.Object( - { - name: Type.String(), - enabled: Type.Boolean(), - }, - { additionalProperties: false } -); -export type CommandItem = Static; - -export const PriceConfigSchema = Type.Object({ - baseMultiplier: Type.Number(), - issueCreatorMultiplier: Type.Number(), - timeLabels: Type.Array(LabelItemSchema), - priorityLabels: Type.Array(LabelItemSchema), - incentives: IncentivesSchema, - defaultLabels: Type.Array(Type.String()), -}); -export type PriceConfig = Static; - -export const SupabaseConfigSchema = Type.Object({ - url: Type.String(), - key: Type.String(), -}); - -export const TelegramBotConfigSchema = Type.Object({ - token: Type.String(), - delay: Type.Number(), -}); - -export const LogNotificationSchema = Type.Object({ - url: Type.String(), - secret: Type.String(), - groupId: Type.Number(), - topicId: Type.Number(), - enabled: Type.Boolean(), -}); - -export type LogNotification = Static; - -export const PayoutConfigSchema = Type.Object({ - networkId: Type.Number(), - rpc: Type.String(), - privateKey: Type.String(), - paymentToken: Type.String(), - permitBaseUrl: Type.String(), -}); - -export const UnassignConfigSchema = Type.Object({ - followUpTime: Type.Number(), - disqualifyTime: Type.Number(), - timeRangeForMaxIssue: Type.Number(), - timeRangeForMaxIssueEnabled: Type.Boolean(), -}); - -export const ModeSchema = Type.Object({ - paymentPermitMaxPrice: Type.Number(), - disableAnalytics: Type.Boolean(), - incentiveMode: Type.Boolean(), - assistivePricing: Type.Boolean(), -}); - -export const AssignSchema = Type.Object({ - bountyHunterMax: Type.Number(), - staleBountyTime: Type.Number(), -}); - -export const LogConfigSchema = Type.Object({ - logEnvironment: Type.String(), - level: Type.Enum(LogLevel), - retryLimit: Type.Number(), -}); - -export const SodiumSchema = Type.Object({ - publicKey: Type.String(), - privateKey: Type.String(), -}); - -export const CommentsSchema = Type.Object({ - promotionComment: Type.String(), -}); - -export const AskSchema = Type.Object({ - apiKey: Type.Optional(Type.String()), - tokenLimit: Type.Number(), -}); - -export const NewContributorGreetingSchema = Type.Object({ - enabled: Type.Boolean(), - header: Type.String(), - helpMenu: Type.Boolean(), - footer: Type.String(), -}); -export type NewContributorGreeting = Static; - -export const CommandConfigSchema = Type.Array(CommandItemSchema); - -export type CommandConfig = Static; -export const WalletSchema = Type.Object({ - registerWalletWithVerification: Type.Boolean(), -}); - -export const AccessControlSchema = Type.Object({ - label: Type.Boolean(), - organization: Type.Boolean(), -}); - -export type AccessControl = Static; - -export const BotConfigSchema = Type.Object({ - log: LogConfigSchema, - price: PriceConfigSchema, - payout: PayoutConfigSchema, - unassign: UnassignConfigSchema, - supabase: SupabaseConfigSchema, - telegram: TelegramBotConfigSchema, - logNotification: LogNotificationSchema, - mode: ModeSchema, - assign: AssignSchema, - sodium: SodiumSchema, - comments: CommentsSchema, - command: CommandConfigSchema, - wallet: WalletSchema, - ask: AskSchema, - accessControl: AccessControlSchema, - newContributorGreeting: NewContributorGreetingSchema, -}); - -export type BotConfig = Static; - -export const StreamlinedCommentSchema = Type.Object({ - login: Type.Optional(Type.String()), - body: Type.Optional(Type.String()), -}); - -export type StreamlinedComment = Static; - -export const GPTResponseSchema = Type.Object({ - answer: Type.Optional(Type.String()), - tokenUsage: Type.Object({ - output: Type.Optional(Type.Number()), - input: Type.Optional(Type.Number()), - total: Type.Optional(Type.Number()), - }), -}); - -export type GPTResponse = Static; - -export const WideConfigSchema = Type.Object( - { - evmNetworkId: Type.Optional(Type.Number()), - priceMultiplier: Type.Optional(Type.Number()), - issueCreatorMultiplier: Type.Optional(Type.Number()), - timeLabels: Type.Optional(Type.Array(LabelItemSchema)), - priorityLabels: Type.Optional(Type.Array(LabelItemSchema)), - paymentPermitMaxPrice: Type.Optional(Type.Number()), - commandSettings: Type.Optional(Type.Array(CommandItemSchema)), - promotionComment: Type.Optional(Type.String()), - disableAnalytics: Type.Optional(Type.Boolean()), - commentIncentives: Type.Optional(Type.Boolean()), - assistivePricing: Type.Optional(Type.Boolean()), - maxConcurrentAssigns: Type.Optional(Type.Number()), - incentives: Type.Optional(IncentivesSchema), - defaultLabels: Type.Optional(Type.Array(Type.String())), - registerWalletWithVerification: Type.Optional(Type.Boolean()), - enableAccessControl: Type.Optional(AccessControlSchema), - openAIKey: Type.Optional(Type.String()), - openAITokenLimit: Type.Optional(Type.Number()), - staleBountyTime: Type.Optional(Type.String()), - privateKeyEncrypted: Type.Optional(Type.String()), - newContributorGreeting: Type.Optional(NewContributorGreetingSchema), - }, - { - additionalProperties: false, - } -); - -export type WideConfig = Static; - -export type WideRepoConfig = WideConfig; - -export const MergedConfigSchema = Type.Object({ - evmNetworkId: Type.Number(), - priceMultiplier: Type.Number(), - privateKeyEncrypted: Type.Optional(Type.String()), - issueCreatorMultiplier: Type.Number(), - timeLabels: Type.Array(LabelItemSchema), - priorityLabels: Type.Array(LabelItemSchema), - paymentPermitMaxPrice: Type.Number(), - commandSettings: Type.Array(CommandItemSchema), - promotionComment: Type.String(), - disableAnalytics: Type.Boolean(), - commentIncentives: Type.Boolean(), - assistivePricing: Type.Boolean(), - maxConcurrentAssigns: Type.Number(), - incentives: IncentivesSchema, - defaultLabels: Type.Array(Type.String()), - registerWalletWithVerification: Type.Boolean(), - enableAccessControl: AccessControlSchema, - openAIKey: Type.Optional(Type.String()), - openAITokenLimit: Type.Optional(Type.Number()), - staleBountyTime: Type.String(), - newContributorGreeting: NewContributorGreetingSchema, - timeRangeForMaxIssue: Type.Number(), - timeRangeForMaxIssueEnabled: Type.Boolean(), - permitBaseUrl: Type.String(), - botDelay: Type.Number(), - followUpTime: Type.String(), - disqualifyTime: Type.String(), -}); - -export type MergedConfig = Static; diff --git a/src/types/configuration-types.ts b/src/types/configuration-types.ts new file mode 100644 index 000000000..0ff6e633c --- /dev/null +++ b/src/types/configuration-types.ts @@ -0,0 +1,124 @@ +import { ObjectOptions, Static, StaticDecode, StringOptions, TProperties, Type as T } from "@sinclair/typebox"; +import ms from "ms"; +import { LogLevel } from "ubiquibot-logger/pretty-logs"; +import { userCommands } from "../handlers/comment/handlers/comment-handler-main"; + +import { ajv } from "../utils/ajv"; +import { validHTMLElements } from "./valid-html-elements"; + +const promotionComment = + "###### If you enjoy the DevPool experience, please follow [Ubiquity on GitHub](https://github.com/ubiquity) and star [this repo](https://github.com/ubiquity/devpool-directory) to show your support. It helps a lot!"; +const defaultGreetingHeader = + "Thank you for contributing! Please be sure to set your wallet address before completing your first task so that you can collect your reward."; + +const htmlEntities = validHTMLElements.map((value) => T.Literal(value)); + +const allHtmlElementsSetToZero = validHTMLElements.reduce((accumulator, current) => { + accumulator[current] = 0; + return accumulator; +}, {} as Record); + +const allCommands = userCommands(false).map((cmd) => cmd.id.replace("/", "")); + +const defaultTimeLabels = ["Time: <1 Hour", "Time: <2 Hours", "Time: <4 Hours", "Time: <1 Day", "Time: <1 Week"]; + +const defaultPriorityLabels = [ + "Priority: 1 (Normal)", + "Priority: 2 (Medium)", + "Priority: 3 (High)", + "Priority: 4 (Urgent)", + "Priority: 5 (Emergency)", +]; + +function strictObject(obj: T, options?: ObjectOptions) { + return T.Object(obj, { additionalProperties: false, default: {}, ...options }); +} + +export function stringDuration(options?: StringOptions) { + return T.Transform(T.String(options)) + .Decode((value) => { + const decoded = ms(value); + if (decoded === undefined || isNaN(decoded)) { + throw new Error(`Invalid duration string: ${value}`); + } + return ms(value); + }) + .Encode((value) => ms(value)); +} + +const envConfigSchema = T.Object({ + WEBHOOK_PROXY_URL: T.Optional(T.String({ format: "uri" })), // optional for production + LOG_LEVEL: T.Enum(LogLevel, { default: LogLevel.DEBUG }), + LOG_RETRY_LIMIT: T.Number({ default: 8 }), + SUPABASE_URL: T.String({ format: "uri" }), + SUPABASE_KEY: T.String(), + PRIVATE_KEY: T.String(), + APP_ID: T.Number(), +}); + +export const validateEnvConfig = ajv.compile(envConfigSchema); +export type EnvConfig = Static; + +const botConfigSchema = strictObject( + { + keys: strictObject({ + evmPrivateEncrypted: T.Optional(T.String()), + openAi: T.Optional(T.String()), + }), + features: strictObject({ + assistivePricing: T.Boolean({ default: false }), + defaultLabels: T.Array(T.String(), { default: [] }), + newContributorGreeting: strictObject({ + enabled: T.Boolean({ default: false }), + header: T.String({ default: defaultGreetingHeader }), + displayHelpMenu: T.Boolean({ default: true }), + footer: T.String({ default: promotionComment }), + }), + publicAccessControl: strictObject({ + setLabel: T.Boolean({ default: true }), + fundExternalClosedIssue: T.Boolean({ default: true }), + }), + isNftRewardEnabled: T.Boolean({ default: false }), + }), + + timers: strictObject({ + reviewDelayTolerance: stringDuration({ default: "1 day" }), + taskStaleTimeoutDuration: stringDuration({ default: "4 weeks" }), + taskFollowUpDuration: stringDuration({ default: "0.5 weeks" }), + taskDisqualifyDuration: stringDuration({ default: "1 week" }), + }), + payments: strictObject({ + maxPermitPrice: T.Number({ default: Number.MAX_SAFE_INTEGER }), + evmNetworkId: T.Number({ default: 1 }), + basePriceMultiplier: T.Number({ default: 1 }), + issueCreatorMultiplier: T.Number({ default: 1 }), + }), + disabledCommands: T.Array(T.String(), { default: allCommands }), + incentives: strictObject({ + comment: strictObject({ + elements: T.Record(T.Union(htmlEntities), T.Number({ default: 0 }), { default: allHtmlElementsSetToZero }), + totals: strictObject({ + character: T.Number({ default: 0, minimum: 0 }), + word: T.Number({ default: 0, minimum: 0 }), + sentence: T.Number({ default: 0, minimum: 0 }), + paragraph: T.Number({ default: 0, minimum: 0 }), + comment: T.Number({ default: 0, minimum: 0 }), + }), + }), + }), + labels: strictObject({ + time: T.Array(T.String(), { default: defaultTimeLabels }), + priority: T.Array(T.String(), { default: defaultPriorityLabels }), + }), + miscellaneous: strictObject({ + maxConcurrentTasks: T.Number({ default: Number.MAX_SAFE_INTEGER }), + promotionComment: T.String({ default: promotionComment }), + registerWalletWithVerification: T.Boolean({ default: false }), + openAiTokenLimit: T.Number({ default: 100000 }), + }), + }, + { default: undefined } // top level object can't have default! +); +export const validateBotConfig = ajv.compile(botConfigSchema); + +export type BotConfig = StaticDecode; diff --git a/src/types/context.ts b/src/types/context.ts new file mode 100644 index 000000000..cef586ce1 --- /dev/null +++ b/src/types/context.ts @@ -0,0 +1,14 @@ +import OpenAI from "openai"; +import { Context as ProbotContext, ProbotOctokit } from "probot"; +import { Logs } from "ubiquibot-logger"; +import { BotConfig } from "./configuration-types"; +import { GitHubPayload } from "./payload"; + +export interface Context { + event: ProbotContext; + config: BotConfig; + openAi: OpenAI | null; + logger: Logs; + payload: GitHubPayload; + octokit: InstanceType; +} diff --git a/src/types/github-events.ts b/src/types/github-events.ts new file mode 100644 index 000000000..67397a629 --- /dev/null +++ b/src/types/github-events.ts @@ -0,0 +1,242 @@ +export enum GitHubEvent { + // "BRANCH_PROTECTION_RULE" = "branch_protection_rule", + "BRANCH_PROTECTION_RULE_CREATED" = "branch_protection_rule.created", + "BRANCH_PROTECTION_RULE_DELETED" = "branch_protection_rule.deleted", + "BRANCH_PROTECTION_RULE_EDITED" = "branch_protection_rule.edited", + // "CHECK_RUN" = "check_run", + "CHECK_RUN_COMPLETED" = "check_run.completed", + "CHECK_RUN_CREATED" = "check_run.created", + "CHECK_RUN_REQUESTED_ACTION" = "check_run.requested_action", + "CHECK_RUN_REREQUESTED" = "check_run.rerequested", + // "CHECK_SUITE" = "check_suite", + "CHECK_SUITE_COMPLETED" = "check_suite.completed", + "CHECK_SUITE_REQUESTED" = "check_suite.requested", + "CHECK_SUITE_REREQUESTED" = "check_suite.rerequested", + // "CODE_SCANNING_ALERT" = "code_scanning_alert", + "CODE_SCANNING_ALERT_APPEARED_IN_BRANCH" = "code_scanning_alert.appeared_in_branch", + "CODE_SCANNING_ALERT_CLOSED_BY_USER" = "code_scanning_alert.closed_by_user", + "CODE_SCANNING_ALERT_CREATED" = "code_scanning_alert.created", + "CODE_SCANNING_ALERT_FIXED" = "code_scanning_alert.fixed", + "CODE_SCANNING_ALERT_REOPENED" = "code_scanning_alert.reopened", + "CODE_SCANNING_ALERT_REOPENED_BY_USER" = "code_scanning_alert.reopened_by_user", + // "COMMIT_COMMENT" = "commit_comment", + "COMMIT_COMMENT_CREATED" = "commit_comment.created", + // "CREATE" = "create", + // "DELETE" = "delete", + // "DEPLOY_KEY" = "deploy_key", + "DEPLOY_KEY_CREATED" = "deploy_key.created", + "DEPLOY_KEY_DELETED" = "deploy_key.deleted", + // "DEPLOYMENT" = "deployment", + "DEPLOYMENT_CREATED" = "deployment.created", + // "DEPLOYMENT_STATUS" = "deployment_status", + "DEPLOYMENT_STATUS_CREATED" = "deployment_status.created", + // "DISCUSSION" = "discussion", + "DISCUSSION_ANSWERED" = "discussion.answered", + "DISCUSSION_CATEGORY_CHANGED" = "discussion.category_changed", + "DISCUSSION_CREATED" = "discussion.created", + "DISCUSSION_DELETED" = "discussion.deleted", + "DISCUSSION_EDITED" = "discussion.edited", + "DISCUSSION_LABELED" = "discussion.labeled", + "DISCUSSION_LOCKED" = "discussion.locked", + "DISCUSSION_PINNED" = "discussion.pinned", + "DISCUSSION_TRANSFERRED" = "discussion.transferred", + "DISCUSSION_UNANSWERED" = "discussion.unanswered", + "DISCUSSION_UNLABELED" = "discussion.unlabeled", + "DISCUSSION_UNLOCKED" = "discussion.unlocked", + "DISCUSSION_UNPINNED" = "discussion.unpinned", + // "DISCUSSION_COMMENT" = "discussion_comment", + "DISCUSSION_COMMENT_CREATED" = "discussion_comment.created", + "DISCUSSION_COMMENT_DELETED" = "discussion_comment.deleted", + "DISCUSSION_COMMENT_EDITED" = "discussion_comment.edited", + // "FORK" = "fork", + // "GITHUB_APP_AUTHORIZATION" = "github_app_authorization", + "GITHUB_APP_AUTHORIZATION_REVOKED" = "github_app_authorization.revoked", + // "GOLLUM" = "gollum", + // "INSTALLATION" = "installation", + "INSTALLATION_CREATED" = "installation.created", + "INSTALLATION_DELETED" = "installation.deleted", + "INSTALLATION_NEW_PERMISSIONS_ACCEPTED" = "installation.new_permissions_accepted", + "INSTALLATION_SUSPEND" = "installation.suspend", + "INSTALLATION_UNSUSPEND" = "installation.unsuspend", + // "INSTALLATION_REPOSITORIES" = "installation_repositories", + "INSTALLATION_REPOSITORIES_ADDED" = "installation_repositories.added", + "INSTALLATION_REPOSITORIES_REMOVED" = "installation_repositories.removed", + // "ISSUE_COMMENT" = "issue_comment", + "ISSUE_COMMENT_CREATED" = "issue_comment.created", + "ISSUE_COMMENT_DELETED" = "issue_comment.deleted", + "ISSUE_COMMENT_EDITED" = "issue_comment.edited", + // "ISSUES" = "issues", + "ISSUES_ASSIGNED" = "issues.assigned", + "ISSUES_CLOSED" = "issues.closed", + "ISSUES_DELETED" = "issues.deleted", + "ISSUES_DEMILESTONED" = "issues.demilestoned", + "ISSUES_EDITED" = "issues.edited", + "ISSUES_LABELED" = "issues.labeled", + "ISSUES_LOCKED" = "issues.locked", + "ISSUES_MILESTONED" = "issues.milestoned", + "ISSUES_OPENED" = "issues.opened", + "ISSUES_PINNED" = "issues.pinned", + "ISSUES_REOPENED" = "issues.reopened", + "ISSUES_TRANSFERRED" = "issues.transferred", + "ISSUES_UNASSIGNED" = "issues.unassigned", + "ISSUES_UNLABELED" = "issues.unlabeled", + "ISSUES_UNLOCKED" = "issues.unlocked", + "ISSUES_UNPINNED" = "issues.unpinned", + // "LABEL" = "label", + "LABEL_CREATED" = "label.created", + "LABEL_DELETED" = "label.deleted", + "LABEL_EDITED" = "label.edited", + // "MARKETPLACE_PURCHASE" = "marketplace_purchase", + "MARKETPLACE_PURCHASE_CANCELLED" = "marketplace_purchase.cancelled", + "MARKETPLACE_PURCHASE_CHANGED" = "marketplace_purchase.changed", + "MARKETPLACE_PURCHASE_PENDING_CHANGE" = "marketplace_purchase.pending_change", + "MARKETPLACE_PURCHASE_PENDING_CHANGE_CANCELLED" = "marketplace_purchase.pending_change_cancelled", + "MARKETPLACE_PURCHASE_PURCHASED" = "marketplace_purchase.purchased", + // "MEMBER" = "member", + "MEMBER_ADDED" = "member.added", + "MEMBER_EDITED" = "member.edited", + "MEMBER_REMOVED" = "member.removed", + // "MEMBERSHIP" = "membership", + "MEMBERSHIP_ADDED" = "membership.added", + "MEMBERSHIP_REMOVED" = "membership.removed", + // "META" = "meta", + "META_DELETED" = "meta.deleted", + // "MILESTONE" = "milestone", + "MILESTONE_CLOSED" = "milestone.closed", + "MILESTONE_CREATED" = "milestone.created", + "MILESTONE_DELETED" = "milestone.deleted", + "MILESTONE_EDITED" = "milestone.edited", + "MILESTONE_OPENED" = "milestone.opened", + // "ORG_BLOCK" = "org_block", + "ORG_BLOCK_BLOCKED" = "org_block.blocked", + "ORG_BLOCK_UNBLOCKED" = "org_block.unblocked", + // "ORGANIZATION" = "organization", + "ORGANIZATION_DELETED" = "organization.deleted", + "ORGANIZATION_MEMBER_ADDED" = "organization.member_added", + "ORGANIZATION_MEMBER_INVITED" = "organization.member_invited", + "ORGANIZATION_MEMBER_REMOVED" = "organization.member_removed", + "ORGANIZATION_RENAMED" = "organization.renamed", + // "PACKAGE" = "package", + "PACKAGE_PUBLISHED" = "package.published", + "PACKAGE_UPDATED" = "package.updated", + // "PAGE_BUILD" = "page_build", + // "PING" = "ping", + // "PROJECT" = "project", + "PROJECT_CLOSED" = "project.closed", + "PROJECT_CREATED" = "project.created", + "PROJECT_DELETED" = "project.deleted", + "PROJECT_EDITED" = "project.edited", + "PROJECT_REOPENED" = "project.reopened", + // "PROJECT_CARD" = "project_card", + "PROJECT_CARD_CONVERTED" = "project_card.converted", + "PROJECT_CARD_CREATED" = "project_card.created", + "PROJECT_CARD_DELETED" = "project_card.deleted", + "PROJECT_CARD_EDITED" = "project_card.edited", + "PROJECT_CARD_MOVED" = "project_card.moved", + // "PROJECT_COLUMN" = "project_column", + "PROJECT_COLUMN_CREATED" = "project_column.created", + "PROJECT_COLUMN_DELETED" = "project_column.deleted", + "PROJECT_COLUMN_EDITED" = "project_column.edited", + "PROJECT_COLUMN_MOVED" = "project_column.moved", + // "PROJECTS_V2_ITEM" = "projects_v2_item", + "PROJECTS_V2_ITEM_ARCHIVED" = "projects_v2_item.archived", + "PROJECTS_V2_ITEM_CONVERTED" = "projects_v2_item.converted", + "PROJECTS_V2_ITEM_CREATED" = "projects_v2_item.created", + "PROJECTS_V2_ITEM_DELETED" = "projects_v2_item.deleted", + "PROJECTS_V2_ITEM_EDITED" = "projects_v2_item.edited", + "PROJECTS_V2_ITEM_REORDERED" = "projects_v2_item.reordered", + "PROJECTS_V2_ITEM_RESTORED" = "projects_v2_item.restored", + // "PUBLIC" = "public", + // "PULL_REQUEST" = "pull_request", + "PULL_REQUEST_ASSIGNED" = "pull_request.assigned", + "PULL_REQUEST_AUTO_MERGE_DISABLED" = "pull_request.auto_merge_disabled", + "PULL_REQUEST_AUTO_MERGE_ENABLED" = "pull_request.auto_merge_enabled", + "PULL_REQUEST_CLOSED" = "pull_request.closed", + "PULL_REQUEST_CONVERTED_TO_DRAFT" = "pull_request.converted_to_draft", + "PULL_REQUEST_EDITED" = "pull_request.edited", + "PULL_REQUEST_LABELED" = "pull_request.labeled", + "PULL_REQUEST_LOCKED" = "pull_request.locked", + "PULL_REQUEST_OPENED" = "pull_request.opened", + "PULL_REQUEST_READY_FOR_REVIEW" = "pull_request.ready_for_review", + "PULL_REQUEST_REOPENED" = "pull_request.reopened", + "PULL_REQUEST_REVIEW_REQUEST_REMOVED" = "pull_request.review_request_removed", + "PULL_REQUEST_REVIEW_REQUESTED" = "pull_request.review_requested", + "PULL_REQUEST_SYNCHRONIZE" = "pull_request.synchronize", + "PULL_REQUEST_UNASSIGNED" = "pull_request.unassigned", + "PULL_REQUEST_UNLABELED" = "pull_request.unlabeled", + "PULL_REQUEST_UNLOCKED" = "pull_request.unlocked", + // "PULL_REQUEST_REVIEW" = "pull_request_review", + "PULL_REQUEST_REVIEW_DISMISSED" = "pull_request_review.dismissed", + "PULL_REQUEST_REVIEW_EDITED" = "pull_request_review.edited", + "PULL_REQUEST_REVIEW_SUBMITTED" = "pull_request_review.submitted", + // "PULL_REQUEST_REVIEW_COMMENT" = "pull_request_review_comment", + "PULL_REQUEST_REVIEW_COMMENT_CREATED" = "pull_request_review_comment.created", + "PULL_REQUEST_REVIEW_COMMENT_DELETED" = "pull_request_review_comment.deleted", + "PULL_REQUEST_REVIEW_COMMENT_EDITED" = "pull_request_review_comment.edited", + // "PULL_REQUEST_REVIEW_THREAD" = "pull_request_review_thread", + "PULL_REQUEST_REVIEW_THREAD_RESOLVED" = "pull_request_review_thread.resolved", + "PULL_REQUEST_REVIEW_THREAD_UNRESOLVED" = "pull_request_review_thread.unresolved", + "PUSH" = "push", + // "RELEASE" = "release", + "RELEASE_CREATED" = "release.created", + "RELEASE_DELETED" = "release.deleted", + "RELEASE_EDITED" = "release.edited", + "RELEASE_PRERELEASED" = "release.prereleased", + "RELEASE_PUBLISHED" = "release.published", + "RELEASE_RELEASED" = "release.released", + "RELEASE_UNPUBLISHED" = "release.unpublished", + // "REPOSITORY" = "repository", + "REPOSITORY_ARCHIVED" = "repository.archived", + "REPOSITORY_CREATED" = "repository.created", + "REPOSITORY_DELETED" = "repository.deleted", + "REPOSITORY_EDITED" = "repository.edited", + "REPOSITORY_PRIVATIZED" = "repository.privatized", + "REPOSITORY_PUBLICIZED" = "repository.publicized", + "REPOSITORY_RENAMED" = "repository.renamed", + "REPOSITORY_TRANSFERRED" = "repository.transferred", + "REPOSITORY_UNARCHIVED" = "repository.unarchived", + // "REPOSITORY_DISPATCH" = "repository_dispatch", + // "REPOSITORY_IMPORT" = "repository_import", + // "REPOSITORY_VULNERABILITY_ALERT" = "repository_vulnerability_alert", + "REPOSITORY_VULNERABILITY_ALERT_CREATE" = "repository_vulnerability_alert.create", + "REPOSITORY_VULNERABILITY_ALERT_DISMISS" = "repository_vulnerability_alert.dismiss", + "REPOSITORY_VULNERABILITY_ALERT_REOPEN" = "repository_vulnerability_alert.reopen", + "REPOSITORY_VULNERABILITY_ALERT_RESOLVE" = "repository_vulnerability_alert.resolve", + // "SECRET_SCANNING_ALERT" = "secret_scanning_alert", + "SECRET_SCANNING_ALERT_CREATED" = "secret_scanning_alert.created", + "SECRET_SCANNING_ALERT_REOPENED" = "secret_scanning_alert.reopened", + "SECRET_SCANNING_ALERT_RESOLVED" = "secret_scanning_alert.resolved", + // "SECURITY_ADVISORY" = "security_advisory", + "SECURITY_ADVISORY_PERFORMED" = "security_advisory.performed", + "SECURITY_ADVISORY_PUBLISHED" = "security_advisory.published", + "SECURITY_ADVISORY_UPDATED" = "security_advisory.updated", + "SECURITY_ADVISORY_WITHDRAWN" = "security_advisory.withdrawn", + // "SPONSORSHIP" = "sponsorship", + "SPONSORSHIP_CANCELLED" = "sponsorship.cancelled", + "SPONSORSHIP_CREATED" = "sponsorship.created", + "SPONSORSHIP_EDITED" = "sponsorship.edited", + "SPONSORSHIP_PENDING_CANCELLATION" = "sponsorship.pending_cancellation", + "SPONSORSHIP_PENDING_TIER_CHANGE" = "sponsorship.pending_tier_change", + "SPONSORSHIP_TIER_CHANGED" = "sponsorship.tier_changed", + // "STAR" = "star", + "STAR_CREATED" = "star.created", + "STAR_DELETED" = "star.deleted", + // "STATUS" = "status", + // "TEAM" = "team", + "TEAM_ADDED_TO_REPOSITORY" = "team.added_to_repository", + "TEAM_CREATED" = "team.created", + "TEAM_DELETED" = "team.deleted", + "TEAM_EDITED" = "team.edited", + "TEAM_REMOVED_FROM_REPOSITORY" = "team.removed_from_repository", + // "TEAM_ADD" = "team_add", + // "WATCH" = "watch", + "WATCH_STARTED" = "watch.started", + // "WORKFLOW_DISPATCH" = "workflow_dispatch", + // "WORKFLOW_JOB" = "workflow_job", + "WORKFLOW_JOB_COMPLETED" = "workflow_job.completed", + "WORKFLOW_JOB_IN_PROGRESS" = "workflow_job.in_progress", + "WORKFLOW_JOB_QUEUED" = "workflow_job.queued", + // "WORKFLOW_RUN" = "workflow_run", + "WORKFLOW_RUN_COMPLETED" = "workflow_run.completed", + "WORKFLOW_RUN_REQUESTED" = "workflow_run.requested", +} diff --git a/src/types/handlers.ts b/src/types/handlers.ts index 5a79f4dd0..698f47e34 100644 --- a/src/types/handlers.ts +++ b/src/types/handlers.ts @@ -1,10 +1,15 @@ -import { Comment } from "./payload"; +import { LogReturn } from "ubiquibot-logger"; +import { Context } from "./context"; -export type CommandsHandler = (args: string) => Promise; -export type ActionHandler = (args?: string) => Promise; -export type CallbackHandler = (issue_number: number, text: string, action: string, reply_to?: Comment) => Promise; -export type PreActionHandler = ActionHandler; -export type PostActionHandler = ActionHandler; +export type HandlerReturnValuesNoVoid = null | string | LogReturn; + +export type MainActionHandler = (context: Context) => Promise; +type CommandsHandler = (context: Context, body: string) => Promise; + +export type PreActionHandler = (context: Context) => Promise; +export type PostActionHandler = (context: Context) => Promise; + +export type WildCardHandler = (context: Context) => Promise; /** * @dev A set of handlers to do a pre/main/post action for a given action @@ -15,15 +20,13 @@ export type PostActionHandler = ActionHandler; */ export type Handler = { pre: PreActionHandler[]; - action: ActionHandler[]; + action: MainActionHandler[]; post: PostActionHandler[]; }; export type UserCommands = { id: string; description: string; + example: string; handler: CommandsHandler; - callback: CallbackHandler; - successComment?: string; - failureComment?: string; }; diff --git a/src/types/index.ts b/src/types/index.ts deleted file mode 100644 index 83eac7e89..000000000 --- a/src/types/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from "./payload"; -export * from "./shared"; -export * from "./label"; -export * from "./handlers"; -export * from "./config"; -export * from "./markdown"; -export * from "./log"; diff --git a/src/types/label.ts b/src/types/label.ts index 48da78856..359595485 100644 --- a/src/types/label.ts +++ b/src/types/label.ts @@ -1,6 +1,6 @@ import { Static, Type } from "@sinclair/typebox"; -export const LabelSchema = Type.Object({ +export const labelSchema = Type.Object({ id: Type.Number(), node_id: Type.String(), url: Type.String(), @@ -10,4 +10,4 @@ export const LabelSchema = Type.Object({ description: Type.Any(), }); -export type Label = Static; +export type Label = Static; diff --git a/src/types/log.ts b/src/types/log.ts deleted file mode 100644 index 8e3e1b913..000000000 --- a/src/types/log.ts +++ /dev/null @@ -1,9 +0,0 @@ -export enum LogLevel { - ERROR = "error", - WARN = "warn", - INFO = "info", - HTTP = "http", - VERBOSE = "verbose", - DEBUG = "debug", - SILLY = "silly", -} diff --git a/src/types/markdown.ts b/src/types/markdown.ts deleted file mode 100644 index 3b5d8f5d3..000000000 --- a/src/types/markdown.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const MarkdownItem = { - Paragraph: "paragraph", - List: "list", - Link: "link", - Text: "text", - Code: "code", - Image: "image", - BlockQuote: "blockquote", -} as const; -export type MarkdownItem = (typeof MarkdownItem)[keyof typeof MarkdownItem]; diff --git a/src/types/openai.ts b/src/types/openai.ts new file mode 100644 index 000000000..e0c94608f --- /dev/null +++ b/src/types/openai.ts @@ -0,0 +1,8 @@ +import { Type as T, Static } from "@sinclair/typebox"; + +const streamlinedCommentSchema = T.Object({ + login: T.Optional(T.String()), + body: T.Optional(T.String()), +}); + +export type StreamlinedComment = Static; diff --git a/src/types/payload.ts b/src/types/payload.ts index 404991852..e97a42963 100644 --- a/src/types/payload.ts +++ b/src/types/payload.ts @@ -1,9 +1,9 @@ // https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads import { Static, Type } from "@sinclair/typebox"; -import { LabelSchema } from "./label"; +import { labelSchema } from "./label"; -export enum GithubEvent { +export enum GitHubEvent { // issues events ISSUES_LABELED = "issues.labeled", ISSUES_UNLABELED = "issues.unlabeled", @@ -28,6 +28,8 @@ export enum GithubEvent { // label LABEL_EDITED = "label.edited", + + REPOSITORY_DISPATCH = "repository_dispatch", } export enum UserType { @@ -39,21 +41,21 @@ export enum UserType { export enum IssueType { OPEN = "open", CLOSED = "closed", - ALL = "all", + // ALL = "all", } export enum StateReason { COMPLETED = "completed", - NOT_PLANNED = "not_planned", + NOT_PLANNED = "not_planned", // these are all used at runtime, not necessarily in the code. REOPENED = "reopened", } -const UserSchema = Type.Object({ +const userSchema = Type.Object({ login: Type.String(), id: Type.Number(), node_id: Type.String(), avatar_url: Type.String(), - gravatar_id: Type.String(), + gravatar_id: Type.Union([Type.Null(), Type.String()]), url: Type.String(), html_url: Type.String(), followers_url: Type.String(), @@ -69,136 +71,156 @@ const UserSchema = Type.Object({ site_admin: Type.Boolean(), }); -const UserProfileSchema = Type.Intersect([ - UserSchema, - Type.Object({ - name: Type.String(), - company: Type.String(), - blog: Type.String(), - location: Type.String(), - email: Type.String(), - hireable: Type.Boolean(), - bio: Type.String(), - twitter_username: Type.String(), - public_repos: Type.Number(), - public_gists: Type.Number(), - followers: Type.Number(), - following: Type.Number(), - created_at: Type.String(), - updated_at: Type.String(), - }), -]); +// const UserProfileSchema = Type.Intersect([ +// UserSchema, +// Type.Object({ +// name: Type.String(), +// company: Type.String(), +// blog: Type.String(), +// location: Type.String(), +// email: Type.String(), +// hireable: Type.Boolean(), +// bio: Type.String(), +// twitter_username: Type.String(), +// public_repos: Type.Number(), +// public_gists: Type.Number(), +// followers: Type.Number(), +// following: Type.Number(), +// created_at: Type.String(), +// updated_at: Type.String(), +// }), +// ]); -export type User = Static; -export type UserProfile = Static; +export type GitHubUser = Static; +// type UserProfile= Static; +export enum AuthorAssociation { + OWNER = "OWNER", + COLLABORATOR = "COLLABORATOR", + MEMBER = "MEMBER", + CONTRIBUTOR = "CONTRIBUTOR", + FIRST_TIMER = "FIRST_TIMER", + FIRST_TIME_CONTRIBUTOR = "FIRST_TIME_CONTRIBUTOR", + NONE = "NONE", +} +// const AuthorAssociation = Type.Enum(_AuthorAssociation); -const IssueSchema = Type.Object({ - url: Type.String(), - repository_url: Type.String(), - labels_url: Type.String(), +const issueSchema = Type.Object({ + assignee: Type.Union([Type.Null(), userSchema]), + assignees: Type.Array(Type.Union([Type.Null(), userSchema])), + author_association: Type.Enum(AuthorAssociation), + body: Type.String(), + closed_at: Type.Union([Type.String({ format: "date-time" }), Type.Null()]), comments_url: Type.String(), + comments: Type.Number(), + created_at: Type.String({ format: "date-time" }), events_url: Type.String(), html_url: Type.String(), id: Type.Number(), - body: Type.Any(), + labels_url: Type.String(), + labels: Type.Array(labelSchema), + locked: Type.Boolean(), node_id: Type.String(), number: Type.Number(), - title: Type.String(), - user: UserSchema, - labels: Type.Array(LabelSchema), - state: Type.Enum(IssueType), + repository_url: Type.String(), state_reason: Type.Union([Type.Enum(StateReason), Type.Null()]), - locked: Type.Boolean(), - assignee: Type.Any(), - assignees: Type.Array(Type.Any()), - comments: Type.Number(), - created_at: Type.String({ format: "date-time" }), + state: Type.Enum(IssueType), + title: Type.String(), updated_at: Type.String({ format: "date-time" }), - closed_at: Type.Any(), - author_association: Type.String(), + url: Type.String(), + user: userSchema, + // OWNER: The author is an owner of the repository. + // COLLABORATOR: The author is a collaborator on the repository. + // MEMBER: The author is a member of the organization that owns the repository. + // CONTRIBUTOR: The author has contributed to the repository but is not a collaborator, member, or owner. + // FIRST_TIMER: The author is a first-time contributor to the repository. + // FIRST_TIME_CONTRIBUTOR: Similar to "FIRST_TIMER," the author is a first-time contributor to the repository. + // NONE: The author does not have any specific association with the repository. }); -export type Issue = Static; -const RepositorySchema = Type.Object({ - id: Type.Number(), - node_id: Type.String(), - name: Type.String(), - full_name: Type.String(), - private: Type.Boolean(), - owner: UserSchema, - html_url: Type.String(), +export type GitHubIssue = Static; + +const repositorySchema = Type.Object({ + allow_forking: Type.Boolean(), + archive_url: Type.String(), + archived: Type.Boolean(), + assignees_url: Type.String(), + blobs_url: Type.String(), + branches_url: Type.String(), + clone_url: Type.String(), + collaborators_url: Type.String(), + comments_url: Type.String(), + commits_url: Type.String(), + compare_url: Type.String(), + contents_url: Type.String(), + contributors_url: Type.String(), + created_at: Type.String({ format: "date-time" }), + default_branch: Type.String(), + deployments_url: Type.String(), description: Type.Union([Type.String(), Type.Null()]), + disabled: Type.Boolean(), + downloads_url: Type.String(), + events_url: Type.String(), fork: Type.Boolean(), - url: Type.String(), + forks_count: Type.Number(), forks_url: Type.String(), - keys_url: Type.String(), - collaborators_url: Type.String(), - teams_url: Type.String(), + forks: Type.Number(), + full_name: Type.String(), + git_commits_url: Type.String(), + git_refs_url: Type.String(), + git_tags_url: Type.String(), + git_url: Type.String(), + has_downloads: Type.Boolean(), + has_issues: Type.Boolean(), + has_pages: Type.Boolean(), + has_projects: Type.Boolean(), + has_wiki: Type.Boolean(), hooks_url: Type.String(), + html_url: Type.String(), + id: Type.Number(), + is_template: Type.Boolean(), + issue_comment_url: Type.String(), issue_events_url: Type.String(), - events_url: Type.String(), - assignees_url: Type.String(), - branches_url: Type.String(), - tags_url: Type.String(), - blobs_url: Type.String(), - git_tags_url: Type.String(), - git_refs_url: Type.String(), - trees_url: Type.String(), - statuses_url: Type.String(), + issues_url: Type.String(), + keys_url: Type.String(), + labels_url: Type.String(), + language: Type.Any(), languages_url: Type.String(), - stargazers_url: Type.String(), - contributors_url: Type.String(), - subscribers_url: Type.String(), - subscription_url: Type.String(), - commits_url: Type.String(), - git_commits_url: Type.String(), - comments_url: Type.String(), - issue_comment_url: Type.String(), - contents_url: Type.String(), - compare_url: Type.String(), + license: Type.Any(), merges_url: Type.String(), - archive_url: Type.String(), - downloads_url: Type.String(), - issues_url: Type.String(), - pulls_url: Type.String(), milestones_url: Type.String(), + name: Type.String(), + node_id: Type.String(), notifications_url: Type.String(), - labels_url: Type.String(), - releases_url: Type.String(), - deployments_url: Type.String(), - created_at: Type.String({ format: "date-time" }), - updated_at: Type.String({ format: "date-time" }), + open_issues_count: Type.Number(), + open_issues: Type.Number(), + owner: userSchema, + private: Type.Boolean(), + pulls_url: Type.String(), pushed_at: Type.String({ format: "date-time" }), - git_url: Type.String(), - ssh_url: Type.String(), - clone_url: Type.String(), - svn_url: Type.String(), + releases_url: Type.String(), size: Type.Number(), + ssh_url: Type.String(), stargazers_count: Type.Number(), - watchers_count: Type.Number(), - language: Type.Any(), - has_issues: Type.Boolean(), - has_projects: Type.Boolean(), - has_downloads: Type.Boolean(), - has_wiki: Type.Boolean(), - has_pages: Type.Boolean(), - forks_count: Type.Number(), - archived: Type.Boolean(), - disabled: Type.Boolean(), - open_issues_count: Type.Number(), - license: Type.Any(), - allow_forking: Type.Boolean(), - is_template: Type.Boolean(), - web_commit_signoff_required: Type.Boolean(), + stargazers_url: Type.String(), + statuses_url: Type.String(), + subscribers_url: Type.String(), + subscription_url: Type.String(), + svn_url: Type.String(), + tags_url: Type.String(), + teams_url: Type.String(), topics: Type.Array(Type.Any()), + trees_url: Type.String(), + updated_at: Type.String({ format: "date-time" }), + url: Type.String(), visibility: Type.String(), - forks: Type.Number(), - open_issues: Type.Number(), + watchers_count: Type.Number(), watchers: Type.Number(), - default_branch: Type.String(), + web_commit_signoff_required: Type.Boolean(), }); -const OrganizationSchema = Type.Object({ +export type GitHubRepository = Static; + +const organizationSchema = Type.Object({ login: Type.String(), id: Type.Number(), node_id: Type.String(), @@ -213,7 +235,7 @@ const OrganizationSchema = Type.Object({ description: Type.Union([Type.String(), Type.Null()]), }); -const CommitsSchema = Type.Object({ +const commitsSchema = Type.Object({ id: Type.String(), distinct: Type.Boolean(), added: Type.Array(Type.String()), @@ -221,31 +243,44 @@ const CommitsSchema = Type.Object({ modified: Type.Array(Type.String()), }); -export type CommitsPayload = Static; +export type GitHubCommitsPayload = Static; -const InstallationSchema = Type.Object({ +const installationSchema = Type.Object({ id: Type.Number(), node_id: Type.String(), }); -export const CommentSchema = Type.Object({ - url: Type.String(), +const commentSchema = Type.Object({ + author_association: Type.String(), + body_html: Type.Optional(Type.String()), + body_text: Type.Optional(Type.String()), + body: Type.String(), + created_at: Type.String({ format: "date-time" }), html_url: Type.String(), - issue_url: Type.String(), id: Type.Number(), + issue_url: Type.String(), node_id: Type.String(), - user: UserSchema, - created_at: Type.String({ format: "date-time" }), updated_at: Type.String({ format: "date-time" }), - author_association: Type.String(), - body: Type.String(), - body_html: Type.Optional(Type.String()), - body_text: Type.Optional(Type.String()), + url: Type.String(), + user: userSchema, + reactions: Type.Object({ + url: Type.String(), + total_count: Type.Number(), + "+1": Type.Number(), + "-1": Type.Number(), + laugh: Type.Number(), + hooray: Type.Number(), + confused: Type.Number(), + heart: Type.Number(), + rocket: Type.Number(), + eyes: Type.Number(), + }), + // performed_via_github_app: Type.Optional(Type.Boolean()), }); -export type Comment = Static; +export type GitHubComment = Static; -export const AssignEventSchema = Type.Object({ +const assignEventSchema = Type.Object({ url: Type.String(), id: Type.Number(), node_id: Type.String(), @@ -253,52 +288,59 @@ export const AssignEventSchema = Type.Object({ commit_id: Type.String(), commit_url: Type.String(), created_at: Type.String({ format: "date-time" }), - actor: UserSchema, - assignee: UserSchema, - assigner: UserSchema, + actor: userSchema, + assignee: userSchema, + assigner: userSchema, }); -export type AssignEvent = Static; +export type GitHubAssignEvent = Static; -const ChangesSchema = Type.Object({ - name: Type.Object({ - from: Type.String(), - }), +const changesSchema = Type.Object({ + body: Type.Optional( + Type.Object({ + from: Type.String(), + }) + ), + name: Type.Optional( + Type.Object({ + from: Type.String(), + }) + ), }); -export const PayloadSchema = Type.Object({ +export const payloadSchema = Type.Object({ action: Type.String(), - issue: Type.Optional(IssueSchema), - label: Type.Optional(LabelSchema), - comment: Type.Optional(CommentSchema), - sender: UserSchema, - repository: RepositorySchema, - organization: Type.Optional(OrganizationSchema), - installation: Type.Optional(InstallationSchema), - repositories_added: Type.Optional(Type.Array(RepositorySchema)), - changes: Type.Optional(ChangesSchema), + issue: Type.Optional(issueSchema), + label: Type.Optional(labelSchema), + comment: Type.Optional(commentSchema), + sender: userSchema, + repository: repositorySchema, + organization: Type.Optional(organizationSchema), + installation: Type.Optional(installationSchema), + repositories_added: Type.Optional(Type.Array(repositorySchema)), + changes: Type.Optional(changesSchema), }); -export type Payload = Static; +export type GitHubPayload = Static; -export const PushSchema = Type.Object({ +const pushSchema = Type.Object({ ref: Type.String(), action: Type.String(), before: Type.String(), after: Type.String(), - repository: RepositorySchema, - sender: UserSchema, + repository: repositorySchema, + sender: userSchema, created: Type.Boolean(), deleted: Type.Boolean(), forced: Type.Boolean(), - commits: Type.Array(CommitsSchema), - head_commit: CommitsSchema, - installation: Type.Optional(InstallationSchema), + commits: Type.Array(commitsSchema), + head_commit: commitsSchema, + installation: Type.Optional(installationSchema), }); -export type PushPayload = Static; +export type GitHubPushPayload = Static; -export const GithubContentSchema = Type.Object({ +const githubContentSchema = Type.Object({ type: Type.String(), encoding: Type.String(), size: Type.Number(), @@ -320,4 +362,69 @@ export const GithubContentSchema = Type.Object({ ]), }); -export type GithubContent = Static; +export type GithubContent = Static; +// type GitHubOrganization = { +// login: string; +// id: number; +// node_id: string; +// url: string; +// repos_url: string; +// events_url: string; +// hooks_url: string; +// issues_url: string; +// members_url: string; +// public_members_url: string; +// avatar_url: string; +// description: string; +// }; + +// type GitHubOrganizationPayload = { +// action: string; +// membership?: { +// url: string; +// state: string; +// role: string; +// organization_url: string; +// user: { +// login: string; +// id: number; +// node_id: string; +// avatar_url: string; +// gravatar_id: string; +// url: string; +// html_url: string; +// followers_url: string; +// following_url: string; +// gists_url: string; +// starred_url: string; +// subscriptions_url: string; +// organizations_url: string; +// repos_url: string; +// events_url: string; +// received_events_url: string; +// type: string; +// site_admin: boolean; +// }; +// }; +// organization: GitHubOrganization; +// sender: { +// login: string; +// id: number; +// node_id: string; +// avatar_url: string; +// gravatar_id: string; +// url: string; +// html_url: string; +// followers_url: string; +// following_url: string; +// gists_url: string; +// starred_url: string; +// subscriptions_url: string; +// organizations_url: string; +// repos_url: string; +// events_url: string; +// received_events_url: string; +// type: string; +// site_admin: boolean; +// }; +// }; diff --git a/src/types/shared.ts b/src/types/shared.ts deleted file mode 100644 index 8a60db53a..000000000 --- a/src/types/shared.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Type } from "@sinclair/typebox"; - -export const TURL = Type.String({ format: "ipv4" }); diff --git a/src/types/static.ts b/src/types/static.ts deleted file mode 100644 index f6e2aeac9..000000000 --- a/src/types/static.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { ParseMode } from "telegraf/types"; - -/** - * @type {Object} MessagePayload - * @property {chatIds} - chatId array ([10001,10002]) - * @property {action} - action name (`new issue` | `new pull request`) - * @property {title} - message title (`feat: support for x`) - * @property {description} - message description (`build: change x for y`) - * @property {id} - issue | pull id (`54`) - * @property {ref} - base url (`https://github.com/x/issues|pull/54`) - * @property {user} - username (`x-user`) - */ -export type TLMessagePayload = { - chatIds: string[]; - action: string; - title: string; - description: string; - id: string; - ref: string; - user: string; -}; - -/** - * @type {Object} FormattedMessagePayload - * @property {chatIds} - chatId array ([10001,10002]) - * @property {text} - formatted text (`new issue: support for x`) - * @property {parseMode} - parseMode (`HTML|Markdown|MarkdownV2`) - */ -export type TLMessageFormattedPayload = { - chatIds: string[]; - text: string; - parseMode: ParseMode; -}; diff --git a/src/types/valid-html-elements.ts b/src/types/valid-html-elements.ts new file mode 100644 index 000000000..b752853bc --- /dev/null +++ b/src/types/valid-html-elements.ts @@ -0,0 +1,110 @@ +export const validHTMLElements: Array = [ + "a", + "abbr", + "address", + "area", + "article", + "aside", + "audio", + "b", + "base", + "bdi", + "bdo", + "blockquote", + "body", + "br", + "button", + "canvas", + "caption", + "cite", + "code", + "col", + "colgroup", + "data", + "datalist", + "dd", + "del", + "details", + "dfn", + "dialog", + "div", + "dl", + "dt", + "em", + "embed", + "fieldset", + "figcaption", + "figure", + "footer", + "form", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "head", + "header", + "hgroup", + "hr", + "html", + "i", + "iframe", + "img", + "input", + "ins", + "kbd", + "label", + "legend", + "li", + "link", + "main", + "map", + "mark", + "meta", + "meter", + "nav", + "noscript", + "object", + "ol", + "optgroup", + "option", + "output", + "p", + "picture", + "pre", + "progress", + "q", + "rp", + "rt", + "ruby", + "s", + "samp", + "script", + "section", + "select", + "small", + "source", + "span", + "strong", + "style", + "sub", + "summary", + "sup", + "table", + "tbody", + "td", + "textarea", + "tfoot", + "th", + "thead", + "time", + "title", + "tr", + "track", + "u", + "ul", + "var", + "video", + "wbr", +]; diff --git a/src/utils/address.ts b/src/utils/address.ts deleted file mode 100644 index adebe3a3c..000000000 --- a/src/utils/address.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const shortenEthAddress = (address: string, len: number) => { - let prefixLength = 6; - let suffixLength = 5; - - if (len > 13) { - const isEven = len % 2 === 0; - prefixLength = isEven ? len / 2 + 1 : Math.ceil(len / 2); - suffixLength = isEven ? len / 2 - 1 : Math.floor(len / 2); - } - const prefix = address.substring(0, prefixLength); - const suffix = address.substring(address.length - suffixLength); - - return `${prefix}...${suffix}`; -}; - -export const formatEthAddress = (address: string) => { - return "`" + address + "`"; -}; diff --git a/src/utils/ajv.ts b/src/utils/ajv.ts index ce632101e..861c9233d 100644 --- a/src/utils/ajv.ts +++ b/src/utils/ajv.ts @@ -1,47 +1,38 @@ -import Ajv, { Schema } from "ajv"; +import Ajv from "ajv"; import addFormats from "ajv-formats"; -export const ajv = addFormats(new Ajv(), { - formats: [ - "date", - "time", - "date-time", - "duration", - "uri", - "uri-reference", - "uri-template", - "email", - "hostname", - "ipv4", - "ipv6", - "regex", - "uuid", - "json-pointer", - "relative-json-pointer", - "byte", - "int32", - "int64", - "float", - "double", - "password", - "binary", - ], -}); - -export function getAdditionalProperties() { - return ajv.errors?.filter((error) => error.keyword === "additionalProperties").map((error) => error.params.additionalProperty); -} - -export function validate(scheme: string | Schema, data: unknown): { valid: true; error: undefined } | { valid: false; error: string } { - const valid = ajv.validate(scheme, data); - if (!valid) { - const additionalProperties = getAdditionalProperties(); - return { - valid: false, - error: `${ajv.errorsText()}. ${ - additionalProperties && additionalProperties.length > 0 ? `Unnecessary properties: ${additionalProperties.join(", ")}` : "" - }`, - }; +export const ajv = addFormats( + new Ajv({ + strict: true, + removeAdditional: false, + useDefaults: true, + allErrors: true, + coerceTypes: true, + }), + { + formats: [ + "date", + "time", + "date-time", + "duration", + "uri", + "uri-reference", + "uri-template", + "email", + "hostname", + "ipv4", + "ipv6", + "regex", + "uuid", + "json-pointer", + "relative-json-pointer", + "byte", + "int32", + "int64", + "float", + "double", + "password", + "binary", + ], } - return { valid: true, error: undefined }; -} +); diff --git a/src/utils/check-github-rate-limit.ts b/src/utils/check-github-rate-limit.ts new file mode 100644 index 000000000..7d73c2145 --- /dev/null +++ b/src/utils/check-github-rate-limit.ts @@ -0,0 +1,18 @@ +import Runtime from "../bindings/bot-runtime"; + +export async function checkRateLimitGit(headers: { "x-ratelimit-remaining"?: string; "x-ratelimit-reset"?: string }) { + const remainingRequests = headers["x-ratelimit-remaining"] ? parseInt(headers["x-ratelimit-remaining"]) : 0; + if (remainingRequests === 0) { + const resetTime = new Date((headers["x-ratelimit-reset"] ? parseInt(headers["x-ratelimit-reset"]) : 0) * 1000); + const now = new Date(); + const timeToWait = resetTime.getTime() - now.getTime(); + const logger = Runtime.getState().logger; + logger.error("No remaining requests.", { resetTime, now, timeToWait }); + await wait(timeToWait); + } + return remainingRequests; +} + +function wait(ms: number) { + return new Promise((r) => setTimeout(r, ms)); +} diff --git a/src/utils/generate-configuration.ts b/src/utils/generate-configuration.ts new file mode 100644 index 000000000..0f16c3aa5 --- /dev/null +++ b/src/utils/generate-configuration.ts @@ -0,0 +1,151 @@ +import { Value } from "@sinclair/typebox/value"; +import { DefinedError } from "ajv"; +import mergeWith from "lodash/merge"; +import { Context as ProbotContext } from "probot"; +import YAML from "yaml"; +import Runtime from "../bindings/bot-runtime"; +import { BotConfig, stringDuration, validateBotConfig } from "../types/configuration-types"; +import { GitHubPayload } from "../types/payload"; + +const UBIQUIBOT_CONFIG_REPOSITORY = "ubiquibot-config"; +const UBIQUIBOT_CONFIG_FULL_PATH = ".github/ubiquibot-config.yml"; + +export async function generateConfiguration(context: ProbotContext): Promise { + const payload = context.payload as GitHubPayload; + + const orgConfig = parseYaml( + await download({ + context, + repository: UBIQUIBOT_CONFIG_REPOSITORY, + owner: payload.organization?.login || payload.repository.owner.login, + }) + ); + + const repoConfig = parseYaml( + await download({ + context, + repository: payload.repository.name, + owner: payload.repository.owner.login, + }) + ); + + const merged = mergeWith({}, orgConfig, repoConfig, (objValue: unknown, srcValue: unknown) => { + if (Array.isArray(objValue) && Array.isArray(srcValue)) { + // if it's string array, concat and remove duplicates + if (objValue.every((value) => typeof value === "string")) { + return [...new Set(objValue.concat(srcValue))]; + } + // otherwise just concat + return objValue.concat(srcValue); + } + }); + + const logger = Runtime.getState().logger; + + const isValid = validateBotConfig(merged); + if (!isValid) { + const errorMessage = getErrorMsg(validateBotConfig.errors as DefinedError[]); + if (errorMessage) { + throw logger.fatal("Invalid merged configuration", { errorMessage }, true); + } + } + + // this will run transform functions + try { + transformConfig(merged); + } catch (err) { + if (err instanceof Error && payload.issue?.number) { + throw logger.fatal("Configuration error", { err }, true); + } + } + + // console.dir(merged, { depth: null, colors: true }); + return merged as BotConfig; +} + +// Transforming the config only works with Typebox and not Ajv +// When you use Decode() it not only transforms the values but also validates the whole config and Typebox doesn't return all errors so we can filter for correct ones +// That's why we have transform every field manually and catch errors +export function transformConfig(config: BotConfig) { + let errorMsg = ""; + try { + config.timers.reviewDelayTolerance = Value.Decode(stringDuration(), config.timers.reviewDelayTolerance); + } catch (err: unknown) { + const decodeError = err as DecodeError; + if (decodeError.value) { + errorMsg += `Invalid reviewDelayTolerance value: ${decodeError.value}\n`; + } + } + try { + config.timers.taskStaleTimeoutDuration = Value.Decode(stringDuration(), config.timers.taskStaleTimeoutDuration); + } catch (err: unknown) { + const decodeError = err as DecodeError; + if (decodeError.value) { + errorMsg += `Invalid taskStaleTimeoutDuration value: ${decodeError.value}\n`; + } + } + try { + config.timers.taskFollowUpDuration = Value.Decode(stringDuration(), config.timers.taskFollowUpDuration); + } catch (err: unknown) { + const decodeError = err as DecodeError; + if (decodeError.value) { + errorMsg += `Invalid taskFollowUpDuration value: ${decodeError.value}\n`; + } + } + try { + config.timers.taskDisqualifyDuration = Value.Decode(stringDuration(), config.timers.taskDisqualifyDuration); + } catch (err: unknown) { + const decodeError = err as DecodeError; + if (decodeError.value) { + errorMsg += `Invalid taskDisqualifyDuration value: ${decodeError.value}\n`; + } + } + if (errorMsg) throw new Error(errorMsg); +} + +function getErrorMsg(errors: DefinedError[]) { + const errorsWithoutStrict = errors.filter((error) => error.keyword !== "additionalProperties"); + return errorsWithoutStrict.length === 0 + ? null + : errorsWithoutStrict.map((error) => error.instancePath.replaceAll("/", ".") + " " + error.message).join("\n"); +} + +async function download({ + context, + repository, + owner, +}: { + context: ProbotContext; + repository: string; + owner: string; +}): Promise { + if (!repository || !owner) throw new Error("Repo or owner is not defined"); + try { + const { data } = await context.octokit.rest.repos.getContent({ + owner, + repo: repository, + path: UBIQUIBOT_CONFIG_FULL_PATH, + mediaType: { format: "raw" }, + }); + return data as unknown as string; // this will be a string if media format is raw + } catch (err) { + return null; + } +} + +export function parseYaml(data: null | string) { + try { + if (data) { + const parsedData = YAML.parse(data); + return parsedData ?? null; + } + } catch (error) { + const logger = Runtime.getState().logger; + logger.fatal("Failed to parse YAML", { error }); + } + return null; +} + +interface DecodeError extends Error { + value?: string; +} diff --git a/src/utils/github.ts b/src/utils/github.ts deleted file mode 100644 index dabfdd006..000000000 --- a/src/utils/github.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { wait } from "../helpers"; - -// explain how this works -/** - * Checks the rate limit for the GitHub API and waits if necessary - * @param headers The headers of the response - * @returns The remaining requests - * @example - * const remainingRequests = await checkRateLimitGit(headers); - * console.log(`Remaining requests: ${remainingRequests}`); - **/ - -export const checkRateLimitGit = async (headers: { "x-ratelimit-remaining"?: string; "x-ratelimit-reset"?: string }) => { - // Check the remaining limit - const remainingRequests = headers["x-ratelimit-remaining"] ? parseInt(headers["x-ratelimit-remaining"]) : 0; - - // If there are no more remaining requests for this hour, we wait for the reset time - if (remainingRequests === 0) { - // const resetTime = new Date(parseInt(headers["x-ratelimit-reset"]! || "0") * 1000); - const resetTime = new Date((headers["x-ratelimit-reset"] ? parseInt(headers["x-ratelimit-reset"]) : 0) * 1000); - const now = new Date(); - const timeToWait = resetTime.getTime() - now.getTime(); - console.log(`No remaining requests. Waiting for ${timeToWait}ms...`); - await wait(timeToWait); - } - - return remainingRequests; -}; diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts deleted file mode 100644 index 3ce69951f..000000000 --- a/src/utils/helpers.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const ErrorDiff = (message: unknown) => { - return "```diff\n! " + message + "\n```"; -}; diff --git a/src/utils/index.ts b/src/utils/index.ts deleted file mode 100644 index 4f3d54df8..000000000 --- a/src/utils/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./ajv"; -export * from "./address"; -export * from "./github"; diff --git a/src/utils/private.ts b/src/utils/private.ts deleted file mode 100644 index 44ba7fb15..000000000 --- a/src/utils/private.ts +++ /dev/null @@ -1,182 +0,0 @@ -import _sodium from "libsodium-wrappers"; -import YAML from "yaml"; -import { MergedConfig, Payload } from "../types"; -import { Context } from "probot"; -import merge from "lodash/merge"; - -import { DefaultConfig } from "../configs"; -import { validate } from "./ajv"; -import { WideConfig, WideRepoConfig, WideConfigSchema } from "../types"; -import { upsertLastCommentToIssue } from "../helpers"; - -const CONFIG_REPO = "ubiquibot-config"; -const CONFIG_PATH = ".github/ubiquibot-config.yml"; -const KEY_NAME = "privateKeyEncrypted"; -const KEY_PREFIX = "HSK_"; - -export const getConfigSuperset = async (context: Context, type: "org" | "repo", filePath: string): Promise => { - try { - const payload = context.payload as Payload; - const repo = type === "org" ? CONFIG_REPO : payload.repository.name; - const owner = type === "org" ? payload.organization?.login : payload.repository.owner.login; - if (!repo || !owner) return undefined; - const { data } = await context.octokit.rest.repos.getContent({ - owner, - repo, - path: filePath, - mediaType: { - format: "raw", - }, - }); - return data as unknown as string; - } catch (error: unknown) { - return undefined; - } -}; - -export interface MergedConfigs { - parsedRepo: WideRepoConfig | undefined; - parsedOrg: WideRepoConfig | undefined; - parsedDefault: MergedConfig; -} - -export const parseYAML = (data?: string): WideConfig | undefined => { - try { - if (data) { - const parsedData = YAML.parse(data); - return parsedData ?? undefined; - } - return undefined; - } catch (error) { - return undefined; - } -}; - -export const getOrgAndRepoFromPath = (path: string) => { - const parts = path.split("/"); - - if (parts.length !== 2) { - return { org: null, repo: null }; - } - - const [org, repo] = parts; - - return { org, repo }; -}; - -export const getPrivateKey = async (cipherText: string): Promise => { - try { - await _sodium.ready; - const sodium = _sodium; - - const privateKey = process.env.X25519_PRIVATE_KEY; - const publicKey = await getScalarKey(privateKey); - - if (!publicKey || !privateKey) { - return undefined; - } - - const binPub = sodium.from_base64(publicKey, sodium.base64_variants.URLSAFE_NO_PADDING); - const binPriv = sodium.from_base64(privateKey, sodium.base64_variants.URLSAFE_NO_PADDING); - const binCipher = sodium.from_base64(cipherText, sodium.base64_variants.URLSAFE_NO_PADDING); - - let walletPrivateKey: string | undefined = sodium.crypto_box_seal_open(binCipher, binPub, binPriv, "text"); - walletPrivateKey = walletPrivateKey.replace(KEY_PREFIX, ""); - return walletPrivateKey; - } catch (error: unknown) { - return undefined; - } -}; - -export const getScalarKey = async (X25519_PRIVATE_KEY: string | undefined): Promise => { - try { - if (X25519_PRIVATE_KEY !== undefined) { - await _sodium.ready; - const sodium = _sodium; - - const binPriv = sodium.from_base64(X25519_PRIVATE_KEY, sodium.base64_variants.URLSAFE_NO_PADDING); - const scalerPub = sodium.crypto_scalarmult_base(binPriv, "base64"); - return scalerPub; - } - return undefined; - } catch (error: unknown) { - return undefined; - } -}; - -const mergeConfigs = (configs: MergedConfigs) => { - return merge({}, configs.parsedDefault, configs.parsedOrg, configs.parsedRepo); -}; - -export const getWideConfig = async (context: Context) => { - const orgConfig = await getConfigSuperset(context, "org", CONFIG_PATH); - const repoConfig = await getConfigSuperset(context, "repo", CONFIG_PATH); - const payload = context.payload as Payload; - - const parsedOrg: WideRepoConfig | undefined = parseYAML(orgConfig); - - if (parsedOrg) { - const { valid, error } = validate(WideConfigSchema, parsedOrg); - if (!valid) { - const err = new Error(`Invalid org config: ${error}`); - if (payload.issue) await upsertLastCommentToIssue(payload.issue.number, err.message); - throw err; - } - } - - const parsedRepo: WideRepoConfig | undefined = parseYAML(repoConfig); - - if (parsedRepo) { - const { valid, error } = validate(WideConfigSchema, parsedRepo); - if (!valid) { - const err = new Error(`Invalid repo config: ${error}`); - if (payload.issue) await upsertLastCommentToIssue(payload.issue.number, err.message); - throw err; - } - } - const parsedDefault: MergedConfig = DefaultConfig; - - let privateKeyDecrypted; - if (parsedRepo && parsedRepo[KEY_NAME]) { - privateKeyDecrypted = await getPrivateKey(parsedRepo[KEY_NAME]); - } else if (parsedOrg && parsedOrg[KEY_NAME]) { - privateKeyDecrypted = await getPrivateKey(parsedOrg[KEY_NAME]); - } else { - privateKeyDecrypted = undefined; - } - - const configs: MergedConfigs = { parsedDefault, parsedOrg, parsedRepo }; - const mergedConfigData: MergedConfig = mergeConfigs(configs); - - const configData = { - networkId: mergedConfigData.evmNetworkId, - privateKey: privateKeyDecrypted ?? "", - assistivePricing: mergedConfigData.assistivePricing, - commandSettings: mergedConfigData.commandSettings, - baseMultiplier: mergedConfigData.priceMultiplier, - issueCreatorMultiplier: mergedConfigData.issueCreatorMultiplier, - timeLabels: mergedConfigData.timeLabels, - priorityLabels: mergedConfigData.priorityLabels, - paymentPermitMaxPrice: mergedConfigData.paymentPermitMaxPrice, - disableAnalytics: mergedConfigData.disableAnalytics, - bountyHunterMax: mergedConfigData.maxConcurrentAssigns, - incentiveMode: mergedConfigData.commentIncentives, - incentives: mergedConfigData.incentives, - defaultLabels: mergedConfigData.defaultLabels, - promotionComment: mergedConfigData.promotionComment, - registerWalletWithVerification: mergedConfigData.registerWalletWithVerification, - enableAccessControl: mergedConfigData.enableAccessControl, - openAIKey: mergedConfigData.openAIKey, - openAITokenLimit: mergedConfigData.openAITokenLimit, - staleBountyTime: mergedConfigData.staleBountyTime, - newContributorGreeting: mergedConfigData.newContributorGreeting, - timeRangeForMaxIssue: mergedConfigData.timeRangeForMaxIssue, - timeRangeForMaxIssueEnabled: mergedConfigData.timeRangeForMaxIssueEnabled, - permitBaseUrl: mergedConfigData.permitBaseUrl, - botDelay: mergedConfigData.botDelay, - followUpTime: mergedConfigData.followUpTime, - disqualifyTime: mergedConfigData.disqualifyTime, - }; - - return configData; -}; diff --git a/src/utils/web-assets.ts b/src/utils/web-assets.ts deleted file mode 100644 index 9b53a3146..000000000 --- a/src/utils/web-assets.ts +++ /dev/null @@ -1,20 +0,0 @@ -import axios from "axios"; -import { createWriteStream } from "fs"; - -export const fetchImage = async (url: string): Promise => { - const dir = "../assets/images/webFlat.png"; - const writer = createWriteStream(dir); - - const response = await axios({ - url, - method: "GET", - responseType: "stream", - }); - - response.data.pipe(writer); - - return new Promise((resolve, reject) => { - writer.on("finish", resolve); - writer.on("error", reject); - }); -}; diff --git a/supabase/.gitignore b/supabase/.gitignore new file mode 100644 index 000000000..773c7c3e0 --- /dev/null +++ b/supabase/.gitignore @@ -0,0 +1,3 @@ +# Supabase +.branches +.temp diff --git a/supabase/README.md b/supabase/README.md index 397affb3f..151131354 100644 --- a/supabase/README.md +++ b/supabase/README.md @@ -1,6 +1,6 @@ # Supabase Database Adapter -[Supabase](https://supabase.com/) is used to store bounty hunters profiles and bounties information. +[Supabase](https://supabase.com/) is used to store contributor profiles and task information. ### How to setup supabase project locally @@ -18,37 +18,37 @@ SUPABASE_KEY=XXX - Run Supabase locally ```sh -yarn supabase start +bun supabase start ``` - Manager database migrations ```sh -yarn supabase migration +bun supabase migration ``` - CI/CD for releasing to production ```sh -yarn supabase db push +bun supabase db push ``` - Manager your supabase projects ```sh -yarn supabase projects +bun supabase projects ``` - Generate types directly from your database schemas ```sh -yarn supabase gen types +bun supabase gen types ``` 3. Link the local project to the supabase project you created. ```sh -yarn supabase link -p PASSWORD --project-ref PROJECT_REF +bun supabase link -p PASSWORD --project-ref PROJECT_REF ``` For more information about arguments, please go through [here](https://supabase.com/docs/reference/cli/supabase-link) diff --git a/supabase/config.toml b/supabase/config.toml index 2708cc34f..2d666002b 100644 --- a/supabase/config.toml +++ b/supabase/config.toml @@ -1,8 +1,9 @@ -# A string used to distinguish different Supabase projects on the same host. Defaults to the working -# directory name when running `supabase init`. -project_id = "supa_demo" +# A string used to distinguish different Supabase projects on the same host. Defaults to the +# working directory name when running `supabase init`. +project_id = "ubiquibot" [api] +enabled = true # Port to use for the API URL. port = 54321 # Schemas to expose in your API. Tables, views and stored procedures in this schema will get API @@ -17,35 +18,65 @@ max_rows = 1000 [db] # Port to use for the local database URL. port = 54322 +# Port used by db diff command to initialise the shadow database. +shadow_port = 54320 # The database major version to use. This has to be the same as your remote database's. Run `SHOW # server_version;` on the remote database to check. major_version = 15 +[db.pooler] +enabled = false +# Port to use for the local connection pooler. +port = 54329 +# Specifies when a server connection can be reused by other clients. +# Configure one of the supported pooler modes: `transaction`, `session`. +pool_mode = "transaction" +# How many server connections to allow per user/database pair. +default_pool_size = 20 +# Maximum number of client connections allowed. +max_client_conn = 100 + +[realtime] +enabled = true +# Bind realtime via either IPv4 or IPv6. (default: IPv6) +# ip_version = "IPv6" + [studio] +enabled = true # Port to use for Supabase Studio. port = 54323 +# External URL of the API server that frontend connects to. +api_url = "http://localhost" # Email testing server. Emails sent with the local dev setup are not actually sent - rather, they # are monitored, and you can view the emails that would have been sent from the web interface. [inbucket] +enabled = true # Port to use for the email testing server web interface. port = 54324 -smtp_port = 54325 -pop3_port = 54326 +# Uncomment to expose additional ports for testing user applications that send emails. +# smtp_port = 54325 +# pop3_port = 54326 [storage] +enabled = true # The maximum file size allowed (e.g. "5MB", "500KB"). file_size_limit = "50MiB" [auth] +enabled = true # The base URL of your website. Used as an allow-list for redirects and for constructing URLs used # in emails. site_url = "http://localhost:3000" # A list of *exact* URLs that auth providers are permitted to redirect to post authentication. additional_redirect_urls = ["https://localhost:3000"] -# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 seconds (one -# week). +# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week). jwt_expiry = 3600 +# If disabled, the refresh token will never expire. +enable_refresh_token_rotation = true +# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds. +# Requires enable_refresh_token_rotation = true. +refresh_token_reuse_interval = 10 # Allow/disallow new user signups to your project. enable_signup = true @@ -58,15 +89,46 @@ double_confirm_changes = true # If enabled, users need to confirm their email address before signing in. enable_confirmations = false +# Uncomment to customize email template +# [auth.email.template.invite] +# subject = "You have been invited" +# content_path = "./supabase/templates/invite.html" + +[auth.sms] +# Allow/disallow new user signups via SMS to your project. +enable_signup = true +# If enabled, users need to confirm their phone number before signing in. +enable_confirmations = false + +# Use pre-defined map of phone number to OTP for testing. +[auth.sms.test_otp] +# 4152127777 = "123456" + +# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`. +[auth.sms.twilio] +enabled = false +account_sid = "" +message_service_sid = "" +# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead: +auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)" + # Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, # `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin`, `notion`, `twitch`, # `twitter`, `slack`, `spotify`, `workos`, `zoom`. [auth.external.apple] enabled = false client_id = "" -secret = "" +# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead: +secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)" # Overrides the default auth redirectUrl. redirect_uri = "" # Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, # or any other third-party OIDC providers. -url = "" \ No newline at end of file +url = "" + +[analytics] +enabled = false +port = 54327 +vector_port = 54328 +# Configure one of the supported backends: `postgres`, `bigquery`. +backend = "postgres" diff --git a/supabase/functions/.vscode/extensions.json b/supabase/functions/.vscode/extensions.json new file mode 100644 index 000000000..74baffcc4 --- /dev/null +++ b/supabase/functions/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["denoland.vscode-deno"] +} diff --git a/supabase/functions/.vscode/settings.json b/supabase/functions/.vscode/settings.json new file mode 100644 index 000000000..97e437224 --- /dev/null +++ b/supabase/functions/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "deno.enable": true, + "deno.lint": true, + "editor.defaultFormatter": "denoland.vscode-deno", + "jest.jestCommandLine": "npx jest" +} diff --git a/supabase/migrations/20230710160900_bounty_hunter_penalty.sql b/supabase/migrations/20230710160900_bounty_hunter_penalty.sql index 0e0ef9260..f40826d7f 100644 --- a/supabase/migrations/20230710160900_bounty_hunter_penalty.sql +++ b/supabase/migrations/20230710160900_bounty_hunter_penalty.sql @@ -1,10 +1,10 @@ CREATE TABLE IF NOT EXISTS penalty ( username text not null, repository_name text not null, - network_id text not null, + evm_network_id text not null, token_address text not null, amount text not null default '0', - PRIMARY KEY (username, repository_name, network_id, token_address) + PRIMARY KEY (username, repository_name, evm_network_id, token_address) ); -- Insert penalty or add penalty amount and return the new penalty amount @@ -13,13 +13,13 @@ returns text as $$ declare updated_penalty_amount text; begin - insert into penalty (username, repository_name, network_id, token_address, amount) VALUES (_username, _repository_name, _network_id, _token_address, _penalty_amount) - on conflict (username, repository_name, network_id, token_address) do update + insert into penalty (username, repository_name, evm_network_id, token_address, amount) VALUES (_username, _repository_name, _network_id, _token_address, _penalty_amount) + on conflict (username, repository_name, evm_network_id, token_address) do update set amount = (penalty.amount::DECIMAL + EXCLUDED.amount::DECIMAL)::TEXT returning amount into updated_penalty_amount; return updated_penalty_amount; end -$$ +$$ language plpgsql; -- Remove penalty amount and return the new penalty amount @@ -30,7 +30,7 @@ $$ begin update penalty set amount = (amount::DECIMAL - _penalty_amount::DECIMAL)::TEXT - where username = _username and repository_name = _repository_name and network_id = _network_id and token_address = _token_address + where username = _username and repository_name = _repository_name and evm_network_id = _network_id and token_address = _token_address returning amount into updated_penalty_amount; return updated_penalty_amount; end diff --git a/supabase/migrations/20230730153700_permit.sql b/supabase/migrations/20230730153700_permit.sql index 8fbfb87ed..8ff996f0a 100644 --- a/supabase/migrations/20230730153700_permit.sql +++ b/supabase/migrations/20230730153700_permit.sql @@ -5,13 +5,13 @@ CREATE TABLE IF NOT EXISTS permits ( organization_id bigint, repository_id bigint NOT NULL, issue_id bigint NOT NULL, - network_id int NOT NULL, - bounty_hunter_id bigint NOT NULL, - bounty_hunter_address text NOT NULL, + evm_network_id int NOT NULL, + contributor_id bigint NOT NULL, + contributor_wallet text NOT NULL, token_address text NOT NULL, payout_amount text NOT NULL, nonce text NOT NULL, deadline text NOT NULL, signature text NOT NULL, - wallet_owner_address text NOT NULL + partner_wallet text NOT NULL ); \ No newline at end of file diff --git a/supabase/seed.sql b/supabase/seed.sql new file mode 100644 index 000000000..e69de29bb diff --git a/tsconfig.json b/tsconfig.json index 6dacfb57e..7da22171c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,20 +1,19 @@ { - "exclude": ["src/reference"], "compilerOptions": { /* Basic Options */ - "incremental": true /* Enable incremental compilation */, + "incremental": false /* Enable incremental compilation */, "target": "ESNEXT" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, - "lib": ["es2015", "es2017"] /* Specify library files to be included in the compilation. */, + "lib": ["DOM", "ESNext"] /* Specify library files to be included in the compilation. */, "allowJs": true /* Allow javascript files to be compiled. */, "checkJs": true /* Report errors in .js files. */, // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ "declaration": true /* Generates corresponding '.d.ts' file. */, // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - "sourceMap": true /* Generates corresponding '.map' file. */, + // "sourceMap": true /* Generates corresponding '.map' file. */, // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "./lib" /* Redirect output structure to the directory. */, - // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + "outDir": "./dist" /* Redirect output structure to the directory. */, + "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, // "composite": true, /* Enable project compilation */ // "tsBuildInfoFile": "./" /* Specify file to store incremental compilation information */, // "removeComments": true, /* Do not emit comments to output. */ @@ -34,7 +33,7 @@ /* Additional Checks */ "noUnusedLocals": true /* Report errors on unused locals. */, "noUnusedParameters": true /* Report errors on unused parameters. */, - "noImplicitReturns": true /* Report error when not all code paths in function return a value. */, + "noImplicitReturns": false /* Report error when not all code paths in function return a value. */, "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */, /* Module Resolution Options */ "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, @@ -50,8 +49,8 @@ /* Source Map Options */ // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + "inlineSourceMap": false /* Emit a single file with source maps instead of having a separate file. */, + "inlineSources": true /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */, /* Experimental Options */ "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */, @@ -59,8 +58,10 @@ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, "resolveJsonModule": true, "pretty": false, - "skipLibCheck": true + "skipLibCheck": true, + "sourceMap": true }, "include": ["src/"], + "exclude": ["src/coverage/", "knip.ts"], "compileOnSave": false } diff --git a/ubiquibot.code-workspace b/ubiquibot.code-workspace new file mode 100644 index 000000000..a9ad457db --- /dev/null +++ b/ubiquibot.code-workspace @@ -0,0 +1,17 @@ +{ + "folders": [ + { + "name": "project-root", + "path": "./" + }, + { + "name": "supabase-functions", + "path": "supabase/functions" + } + ], + "settings": { + "files.exclude": { + "supabase/functions/": true + } + } +} diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index 65e3ead1b..000000000 --- a/yarn.lock +++ /dev/null @@ -1,9750 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@aashutoshrathi/word-wrap@^1.2.3": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" - integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== - -"@actions/core@^1.10.0", "@actions/core@^1.2.6": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.10.0.tgz#44551c3c71163949a2f06e94d9ca2157a0cfac4f" - integrity sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug== - dependencies: - "@actions/http-client" "^2.0.1" - uuid "^8.3.2" - -"@actions/http-client@^2.0.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@actions/http-client/-/http-client-2.1.1.tgz#a8e97699c315bed0ecaeaaeb640948470d4586a0" - integrity sha512-qhrkRMB40bbbLo7gF+0vu+X+UawOvQQqNAA/5Unx774RS8poaOhThDOG6BGmxvAnxhQnDp2BG/ZUm65xZILTpw== - dependencies: - tunnel "^0.0.6" - -"@ampproject/remapping@^2.2.0": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" - integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.13": - version "7.22.13" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" - integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== - dependencies: - "@babel/highlight" "^7.22.13" - chalk "^2.4.2" - -"@babel/compat-data@^7.22.9": - version "7.22.9" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" - integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== - -"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.5": - version "7.22.17" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.17.tgz#2f9b0b395985967203514b24ee50f9fd0639c866" - integrity sha512-2EENLmhpwplDux5PSsZnSbnSkB3tZ6QTksgO25xwEL7pIDcNOMhF5v/s6RzwjMZzZzw9Ofc30gHv5ChCC8pifQ== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.22.15" - "@babel/helper-compilation-targets" "^7.22.15" - "@babel/helper-module-transforms" "^7.22.17" - "@babel/helpers" "^7.22.15" - "@babel/parser" "^7.22.16" - "@babel/template" "^7.22.15" - "@babel/traverse" "^7.22.17" - "@babel/types" "^7.22.17" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/generator@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.15.tgz#1564189c7ec94cb8f77b5e8a90c4d200d21b2339" - integrity sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA== - dependencies: - "@babel/types" "^7.22.15" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - -"@babel/helper-compilation-targets@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52" - integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw== - dependencies: - "@babel/compat-data" "^7.22.9" - "@babel/helper-validator-option" "^7.22.15" - browserslist "^4.21.9" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-environment-visitor@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" - integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== - -"@babel/helper-function-name@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" - integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== - dependencies: - "@babel/template" "^7.22.5" - "@babel/types" "^7.22.5" - -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-module-imports@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" - integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== - dependencies: - "@babel/types" "^7.22.15" - -"@babel/helper-module-transforms@^7.22.17": - version "7.22.17" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz#7edf129097a51ccc12443adbc6320e90eab76693" - integrity sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ== - dependencies: - "@babel/helper-environment-visitor" "^7.22.5" - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-simple-access" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.15" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" - integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== - -"@babel/helper-simple-access@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" - integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-string-parser@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" - integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== - -"@babel/helper-validator-identifier@^7.22.15", "@babel/helper-validator-identifier@^7.22.5": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz#601fa28e4cc06786c18912dca138cec73b882044" - integrity sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ== - -"@babel/helper-validator-option@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040" - integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA== - -"@babel/helpers@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.15.tgz#f09c3df31e86e3ea0b7ff7556d85cdebd47ea6f1" - integrity sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/traverse" "^7.22.15" - "@babel/types" "^7.22.15" - -"@babel/highlight@^7.22.13": - version "7.22.13" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.13.tgz#9cda839e5d3be9ca9e8c26b6dd69e7548f0cbf16" - integrity sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ== - dependencies: - "@babel/helper-validator-identifier" "^7.22.5" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.22.16": - version "7.22.16" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95" - integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA== - -"@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-bigint@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" - integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.8.3": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-import-meta@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" - integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-top-level-await@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/template@^7.22.15", "@babel/template@^7.22.5", "@babel/template@^7.3.3": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" - integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/parser" "^7.22.15" - "@babel/types" "^7.22.15" - -"@babel/traverse@^7.1.0", "@babel/traverse@^7.22.15", "@babel/traverse@^7.22.17": - version "7.22.17" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.17.tgz#b23c203ab3707e3be816043081b4a994fcacec44" - integrity sha512-xK4Uwm0JnAMvxYZxOVecss85WxTEIbTa7bnGyf/+EgCL5Zt3U7htUpEOWv9detPlamGKuRzCqw74xVglDWpPdg== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.22.15" - "@babel/helper-environment-visitor" "^7.22.5" - "@babel/helper-function-name" "^7.22.5" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.22.16" - "@babel/types" "^7.22.17" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.17", "@babel/types@^7.22.5", "@babel/types@^7.3.3": - version "7.22.17" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.17.tgz#f753352c4610ffddf9c8bc6823f9ff03e2303eee" - integrity sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg== - dependencies: - "@babel/helper-string-parser" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.15" - to-fast-properties "^2.0.0" - -"@bcoe/v8-coverage@^0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" - integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== - -"@cnakazawa/watch@^1.0.3": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" - integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== - dependencies: - exec-sh "^0.3.2" - minimist "^1.2.0" - -"@commitlint/cli@^17.4.3": - version "17.7.1" - resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-17.7.1.tgz#f3ab35bd38d82fcd4ab03ec5a1e9db26d57fe1b0" - integrity sha512-BCm/AT06SNCQtvFv921iNhudOHuY16LswT0R3OeolVGLk8oP+Rk9TfQfgjH7QPMjhvp76bNqGFEcpKojxUNW1g== - dependencies: - "@commitlint/format" "^17.4.4" - "@commitlint/lint" "^17.7.0" - "@commitlint/load" "^17.7.1" - "@commitlint/read" "^17.5.1" - "@commitlint/types" "^17.4.4" - execa "^5.0.0" - lodash.isfunction "^3.0.9" - resolve-from "5.0.0" - resolve-global "1.0.0" - yargs "^17.0.0" - -"@commitlint/config-conventional@^17.4.3": - version "17.7.0" - resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-17.7.0.tgz#1bbf2bce7851db63c1a8aa8d924277ad4938247e" - integrity sha512-iicqh2o6et+9kWaqsQiEYZzfLbtoWv9uZl8kbI8EGfnc0HeGafQBF7AJ0ylN9D/2kj6txltsdyQs8+2fTMwWEw== - dependencies: - conventional-changelog-conventionalcommits "^6.1.0" - -"@commitlint/config-validator@^17.6.7": - version "17.6.7" - resolved "https://registry.yarnpkg.com/@commitlint/config-validator/-/config-validator-17.6.7.tgz#c664d42a1ecf5040a3bb0843845150f55734df41" - integrity sha512-vJSncmnzwMvpr3lIcm0I8YVVDJTzyjy7NZAeXbTXy+MPUdAr9pKyyg7Tx/ebOQ9kqzE6O9WT6jg2164br5UdsQ== - dependencies: - "@commitlint/types" "^17.4.4" - ajv "^8.11.0" - -"@commitlint/ensure@^17.6.7": - version "17.6.7" - resolved "https://registry.yarnpkg.com/@commitlint/ensure/-/ensure-17.6.7.tgz#77a77a0c05e6a1c34589f59e82e6cb937101fc4b" - integrity sha512-mfDJOd1/O/eIb/h4qwXzUxkmskXDL9vNPnZ4AKYKiZALz4vHzwMxBSYtyL2mUIDeU9DRSpEUins8SeKtFkYHSw== - dependencies: - "@commitlint/types" "^17.4.4" - 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" - -"@commitlint/execute-rule@^17.4.0": - version "17.4.0" - resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-17.4.0.tgz#4518e77958893d0a5835babe65bf87e2638f6939" - integrity sha512-LIgYXuCSO5Gvtc0t9bebAMSwd68ewzmqLypqI2Kke1rqOqqDbMpYcYfoPfFlv9eyLIh4jocHWwCK5FS7z9icUA== - -"@commitlint/format@^17.4.4": - version "17.4.4" - resolved "https://registry.yarnpkg.com/@commitlint/format/-/format-17.4.4.tgz#0f6e1b4d7a301c7b1dfd4b6334edd97fc050b9f5" - integrity sha512-+IS7vpC4Gd/x+uyQPTAt3hXs5NxnkqAZ3aqrHd5Bx/R9skyCAWusNlNbw3InDbAK6j166D9asQM8fnmYIa+CXQ== - dependencies: - "@commitlint/types" "^17.4.4" - chalk "^4.1.0" - -"@commitlint/is-ignored@^17.7.0": - version "17.7.0" - resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-17.7.0.tgz#df9b284420bdb1aed5fdb2be44f4e98cc4826014" - integrity sha512-043rA7m45tyEfW7Zv2vZHF++176MLHH9h70fnPoYlB1slKBeKl8BwNIlnPg4xBdRBVNPaCqvXxWswx2GR4c9Hw== - dependencies: - "@commitlint/types" "^17.4.4" - semver "7.5.4" - -"@commitlint/lint@^17.7.0": - version "17.7.0" - resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-17.7.0.tgz#33f831298dc43679e4de6b088aea63d1f884c7e7" - integrity sha512-TCQihm7/uszA5z1Ux1vw+Nf3yHTgicus/+9HiUQk+kRSQawByxZNESeQoX9ujfVd3r4Sa+3fn0JQAguG4xvvbA== - dependencies: - "@commitlint/is-ignored" "^17.7.0" - "@commitlint/parse" "^17.7.0" - "@commitlint/rules" "^17.7.0" - "@commitlint/types" "^17.4.4" - -"@commitlint/load@^17.7.1": - version "17.7.1" - resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-17.7.1.tgz#0723b11723a20043a304a74960602dead89b5cdd" - integrity sha512-S/QSOjE1ztdogYj61p6n3UbkUvweR17FQ0zDbNtoTLc+Hz7vvfS7ehoTMQ27hPSjVBpp7SzEcOQu081RLjKHJQ== - dependencies: - "@commitlint/config-validator" "^17.6.7" - "@commitlint/execute-rule" "^17.4.0" - "@commitlint/resolve-extends" "^17.6.7" - "@commitlint/types" "^17.4.4" - "@types/node" "20.4.7" - chalk "^4.1.0" - cosmiconfig "^8.0.0" - cosmiconfig-typescript-loader "^4.0.0" - lodash.isplainobject "^4.0.6" - lodash.merge "^4.6.2" - lodash.uniq "^4.5.0" - resolve-from "^5.0.0" - ts-node "^10.8.1" - typescript "^4.6.4 || ^5.0.0" - -"@commitlint/message@^17.4.2": - version "17.4.2" - resolved "https://registry.yarnpkg.com/@commitlint/message/-/message-17.4.2.tgz#f4753a79701ad6db6db21f69076e34de6580e22c" - integrity sha512-3XMNbzB+3bhKA1hSAWPCQA3lNxR4zaeQAQcHj0Hx5sVdO6ryXtgUBGGv+1ZCLMgAPRixuc6en+iNAzZ4NzAa8Q== - -"@commitlint/parse@^17.7.0": - version "17.7.0" - resolved "https://registry.yarnpkg.com/@commitlint/parse/-/parse-17.7.0.tgz#aacb2d189e50ab8454154b1df150aaf20478ae47" - integrity sha512-dIvFNUMCUHqq5Abv80mIEjLVfw8QNuA4DS7OWip4pcK/3h5wggmjVnlwGCDvDChkw2TjK1K6O+tAEV78oxjxag== - dependencies: - "@commitlint/types" "^17.4.4" - conventional-changelog-angular "^6.0.0" - conventional-commits-parser "^4.0.0" - -"@commitlint/read@^17.5.1": - version "17.5.1" - resolved "https://registry.yarnpkg.com/@commitlint/read/-/read-17.5.1.tgz#fec903b766e2c41e3cefa80630040fcaba4f786c" - integrity sha512-7IhfvEvB//p9aYW09YVclHbdf1u7g7QhxeYW9ZHSO8Huzp8Rz7m05aCO1mFG7G8M+7yfFnXB5xOmG18brqQIBg== - dependencies: - "@commitlint/top-level" "^17.4.0" - "@commitlint/types" "^17.4.4" - fs-extra "^11.0.0" - git-raw-commits "^2.0.11" - minimist "^1.2.6" - -"@commitlint/resolve-extends@^17.6.7": - version "17.6.7" - resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-17.6.7.tgz#9c53a4601c96ab2dd20b90fb35c988639307735d" - integrity sha512-PfeoAwLHtbOaC9bGn/FADN156CqkFz6ZKiVDMjuC2N5N0740Ke56rKU7Wxdwya8R8xzLK9vZzHgNbuGhaOVKIg== - dependencies: - "@commitlint/config-validator" "^17.6.7" - "@commitlint/types" "^17.4.4" - import-fresh "^3.0.0" - lodash.mergewith "^4.6.2" - resolve-from "^5.0.0" - resolve-global "^1.0.0" - -"@commitlint/rules@^17.7.0": - version "17.7.0" - resolved "https://registry.yarnpkg.com/@commitlint/rules/-/rules-17.7.0.tgz#b97a4933c5cba11a659a19ee467f6f000f31533e" - integrity sha512-J3qTh0+ilUE5folSaoK91ByOb8XeQjiGcdIdiB/8UT1/Rd1itKo0ju/eQVGyFzgTMYt8HrDJnGTmNWwcMR1rmA== - dependencies: - "@commitlint/ensure" "^17.6.7" - "@commitlint/message" "^17.4.2" - "@commitlint/to-lines" "^17.4.0" - "@commitlint/types" "^17.4.4" - execa "^5.0.0" - -"@commitlint/to-lines@^17.4.0": - version "17.4.0" - resolved "https://registry.yarnpkg.com/@commitlint/to-lines/-/to-lines-17.4.0.tgz#9bd02e911e7d4eab3fb4a50376c4c6d331e10d8d" - integrity sha512-LcIy/6ZZolsfwDUWfN1mJ+co09soSuNASfKEU5sCmgFCvX5iHwRYLiIuoqXzOVDYOy7E7IcHilr/KS0e5T+0Hg== - -"@commitlint/top-level@^17.4.0": - version "17.4.0" - resolved "https://registry.yarnpkg.com/@commitlint/top-level/-/top-level-17.4.0.tgz#540cac8290044cf846fbdd99f5cc51e8ac5f27d6" - integrity sha512-/1loE/g+dTTQgHnjoCy0AexKAEFyHsR2zRB4NWrZ6lZSMIxAhBJnmCqwao7b4H8888PsfoTBCLBYIw8vGnej8g== - dependencies: - find-up "^5.0.0" - -"@commitlint/types@^17.4.4": - version "17.4.4" - resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-17.4.4.tgz#1416df936e9aad0d6a7bbc979ecc31e55dade662" - integrity sha512-amRN8tRLYOsxRr6mTnGGGvB5EmW/4DDjLMgiwK3CCVEmN6Sr/6xePGEpWaspKkckILuUORCwe6VfDBw6uj4axQ== - dependencies: - chalk "^4.1.0" - -"@cspell/cspell-bundled-dicts@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-7.0.0.tgz#aea8a596a40748ed3e59ba4edd4fe73c0618d4f7" - integrity sha512-qfBAS4W35+loOfbprBDS8nN0Eitl9wmuPE8GQLbwYj9Qj+COlLg57KECeXF8cgGnHkahrIkc3t6V6eFF8nhXQw== - dependencies: - "@cspell/dict-ada" "^4.0.2" - "@cspell/dict-aws" "^4.0.0" - "@cspell/dict-bash" "^4.1.1" - "@cspell/dict-companies" "^3.0.19" - "@cspell/dict-cpp" "^5.0.4" - "@cspell/dict-cryptocurrencies" "^3.0.1" - "@cspell/dict-csharp" "^4.0.2" - "@cspell/dict-css" "^4.0.6" - "@cspell/dict-dart" "^2.0.3" - "@cspell/dict-django" "^4.1.0" - "@cspell/dict-docker" "^1.1.7" - "@cspell/dict-dotnet" "^5.0.0" - "@cspell/dict-elixir" "^4.0.3" - "@cspell/dict-en-common-misspellings" "^1.0.2" - "@cspell/dict-en-gb" "1.1.33" - "@cspell/dict-en_us" "^4.3.6" - "@cspell/dict-filetypes" "^3.0.1" - "@cspell/dict-fonts" "^4.0.0" - "@cspell/dict-fsharp" "^1.0.0" - "@cspell/dict-fullstack" "^3.1.5" - "@cspell/dict-gaming-terms" "^1.0.4" - "@cspell/dict-git" "^2.0.0" - "@cspell/dict-golang" "^6.0.2" - "@cspell/dict-haskell" "^4.0.1" - "@cspell/dict-html" "^4.0.3" - "@cspell/dict-html-symbol-entities" "^4.0.0" - "@cspell/dict-java" "^5.0.5" - "@cspell/dict-k8s" "^1.0.1" - "@cspell/dict-latex" "^4.0.0" - "@cspell/dict-lorem-ipsum" "^4.0.0" - "@cspell/dict-lua" "^4.0.1" - "@cspell/dict-node" "^4.0.2" - "@cspell/dict-npm" "^5.0.8" - "@cspell/dict-php" "^4.0.1" - "@cspell/dict-powershell" "^5.0.2" - "@cspell/dict-public-licenses" "^2.0.3" - "@cspell/dict-python" "^4.1.5" - "@cspell/dict-r" "^2.0.1" - "@cspell/dict-ruby" "^5.0.0" - "@cspell/dict-rust" "^4.0.1" - "@cspell/dict-scala" "^5.0.0" - "@cspell/dict-software-terms" "^3.2.1" - "@cspell/dict-sql" "^2.1.1" - "@cspell/dict-svelte" "^1.0.2" - "@cspell/dict-swift" "^2.0.1" - "@cspell/dict-typescript" "^3.1.1" - "@cspell/dict-vue" "^3.0.0" - -"@cspell/cspell-json-reporter@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@cspell/cspell-json-reporter/-/cspell-json-reporter-7.0.0.tgz#7d04d10b4c7df678847ac94bacf4bcc8740ad719" - integrity sha512-8OheTVzwwfOQqPZe3Enbe1F7Y0djjGunk5K7aC5MyXc3BuIV7Cx13xWo2gfAjiHBRuO5lqg9qidEfp6NE33amg== - dependencies: - "@cspell/cspell-types" "7.0.0" - -"@cspell/cspell-pipe@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@cspell/cspell-pipe/-/cspell-pipe-7.0.0.tgz#a1fdb9a8e31d445b4bf48c49c71cf36769ad9de2" - integrity sha512-MmQeLyyS5rZ/VvRtHGOLFUcCF9zy01WpWYthLZB61o96HCokqtlN4BBBPLYNxrotFNA4syVy9Si/wTxsC9oTiA== - -"@cspell/cspell-service-bus@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@cspell/cspell-service-bus/-/cspell-service-bus-7.0.0.tgz#b764fda9f8d02cfe6cc4df12a290ad4a2f4a94f8" - integrity sha512-0YMM5SJY+XooOTEoo5+xuqTBLO87FP6QR8OBLBDeWNHvON9M4TpeAAN5K+IM0vMSFzgt1aSSMJNO0HSmxn17Yw== - -"@cspell/cspell-types@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@cspell/cspell-types/-/cspell-types-7.0.0.tgz#d4fbe255c9e69b9785cf274e408cf183ba4f1ab3" - integrity sha512-b/Dee5lb362ODlEK+kQcUDJfCprDRUFWcddo5tyzsYm3ID08ll6+DzCtfRxf48isyX1tL7uBKMj/iIpAhRNu9Q== - -"@cspell/dict-ada@^4.0.2": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@cspell/dict-ada/-/dict-ada-4.0.2.tgz#8da2216660aeb831a0d9055399a364a01db5805a" - integrity sha512-0kENOWQeHjUlfyId/aCM/mKXtkEgV0Zu2RhUXCBr4hHo9F9vph+Uu8Ww2b0i5a4ZixoIkudGA+eJvyxrG1jUpA== - -"@cspell/dict-aws@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@cspell/dict-aws/-/dict-aws-4.0.0.tgz#ab71fe0c05d9ad662d27495e74361bdcb5b470eb" - integrity sha512-1YkCMWuna/EGIDN/zKkW+j98/55mxigftrSFgsehXhPld+ZMJM5J9UuBA88YfL7+/ETvBdd7mwW6IwWsC+/ltQ== - -"@cspell/dict-bash@^4.1.1": - version "4.1.1" - resolved "https://registry.yarnpkg.com/@cspell/dict-bash/-/dict-bash-4.1.1.tgz#fe28016096f44d4a09fe4c5bcaf6fa40f33d98c6" - integrity sha512-8czAa/Mh96wu2xr0RXQEGMTBUGkTvYn/Pb0o+gqOO1YW+poXGQc3gx0YPqILDryP/KCERrNvkWUJz3iGbvwC2A== - -"@cspell/dict-companies@^3.0.19": - version "3.0.19" - resolved "https://registry.yarnpkg.com/@cspell/dict-companies/-/dict-companies-3.0.19.tgz#ac7ecaf7fe6568a93ca983a4f72bb64328864b2e" - integrity sha512-hO7rS4DhFA333qyvf89wIVoclCtXe/2sftY6aS0oMIH1bMZLjLx2B2sQJj6dCiu6gG/By1S9YZ0fXabiPk2Tkg== - -"@cspell/dict-cpp@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@cspell/dict-cpp/-/dict-cpp-5.0.4.tgz#2c237dd5d690ee7464c612fd0ef8f2244359d97f" - integrity sha512-Vmz/CCb2d91ES5juaO8+CFWeTa2AFsbpR8bkCPJq+P8cRP16+37tY0zNXEBSK/1ur4MakaRf76jeQBijpZxw0Q== - -"@cspell/dict-cryptocurrencies@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-3.0.1.tgz#de1c235d6427946b679d23aacff12fea94e6385b" - integrity sha512-Tdlr0Ahpp5yxtwM0ukC13V6+uYCI0p9fCRGMGZt36rWv8JQZHIuHfehNl7FB/Qc09NCF7p5ep0GXbL+sVTd/+w== - -"@cspell/dict-csharp@^4.0.2": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@cspell/dict-csharp/-/dict-csharp-4.0.2.tgz#e55659dbe594e744d86b1baf0f3397fe57b1e283" - integrity sha512-1JMofhLK+4p4KairF75D3A924m5ERMgd1GvzhwK2geuYgd2ZKuGW72gvXpIV7aGf52E3Uu1kDXxxGAiZ5uVG7g== - -"@cspell/dict-css@^4.0.6": - version "4.0.6" - resolved "https://registry.yarnpkg.com/@cspell/dict-css/-/dict-css-4.0.6.tgz#39cf199e68d6e17b9518938fa64368cec2f7f9ca" - integrity sha512-2Lo8W2ezHmGgY8cWFr4RUwnjbndna5mokpCK/DuxGILQnuajR0J31ANQOXj/8iZM2phFB93ZzMNk/0c04TDfSQ== - -"@cspell/dict-dart@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@cspell/dict-dart/-/dict-dart-2.0.3.tgz#75e7ffe47d5889c2c831af35acdd92ebdbd4cf12" - integrity sha512-cLkwo1KT5CJY5N5RJVHks2genFkNCl/WLfj+0fFjqNR+tk3tBI1LY7ldr9piCtSFSm4x9pO1x6IV3kRUY1lLiw== - -"@cspell/dict-data-science@^1.0.0": - version "1.0.10" - resolved "https://registry.yarnpkg.com/@cspell/dict-data-science/-/dict-data-science-1.0.10.tgz#88beefd1937fd8c7d94bb3d60f0e9c1b3c428ad8" - integrity sha512-7ZsRCnW0f4Bdo6Cqq8V4gHr8K58h+MP8majcDeMNhpMFUPiiSnvKsDuG9V5jciI/0t+lptPrZwGGIVEDF4Kqtg== - -"@cspell/dict-django@^4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@cspell/dict-django/-/dict-django-4.1.0.tgz#2d4b765daf3c83e733ef3e06887ea34403a4de7a" - integrity sha512-bKJ4gPyrf+1c78Z0Oc4trEB9MuhcB+Yg+uTTWsvhY6O2ncFYbB/LbEZfqhfmmuK/XJJixXfI1laF2zicyf+l0w== - -"@cspell/dict-docker@^1.1.7": - version "1.1.7" - resolved "https://registry.yarnpkg.com/@cspell/dict-docker/-/dict-docker-1.1.7.tgz#bcf933283fbdfef19c71a642e7e8c38baf9014f2" - integrity sha512-XlXHAr822euV36GGsl2J1CkBIVg3fZ6879ZOg5dxTIssuhUOCiV2BuzKZmt6aIFmcdPmR14+9i9Xq+3zuxeX0A== - -"@cspell/dict-dotnet@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@cspell/dict-dotnet/-/dict-dotnet-5.0.0.tgz#13690aafe14b240ad17a30225ac1ec29a5a6a510" - integrity sha512-EOwGd533v47aP5QYV8GlSSKkmM9Eq8P3G/eBzSpH3Nl2+IneDOYOBLEUraHuiCtnOkNsz0xtZHArYhAB2bHWAw== - -"@cspell/dict-elixir@^4.0.3": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@cspell/dict-elixir/-/dict-elixir-4.0.3.tgz#57c25843e46cf3463f97da72d9ef8e37c818296f" - integrity sha512-g+uKLWvOp9IEZvrIvBPTr/oaO6619uH/wyqypqvwpmnmpjcfi8+/hqZH8YNKt15oviK8k4CkINIqNhyndG9d9Q== - -"@cspell/dict-en-common-misspellings@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@cspell/dict-en-common-misspellings/-/dict-en-common-misspellings-1.0.2.tgz#3c4ebab8e9e906d66d60f53c8f8c2e77b7f108e7" - integrity sha512-jg7ZQZpZH7+aAxNBlcAG4tGhYF6Ksy+QS5Df73Oo+XyckBjC9QS+PrRwLTeYoFIgXy5j3ICParK5r3MSSoL4gw== - -"@cspell/dict-en-gb@1.1.33": - version "1.1.33" - resolved "https://registry.yarnpkg.com/@cspell/dict-en-gb/-/dict-en-gb-1.1.33.tgz#7f1fd90fc364a5cb77111b5438fc9fcf9cc6da0e" - integrity sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g== - -"@cspell/dict-en_us@^4.3.6": - version "4.3.6" - resolved "https://registry.yarnpkg.com/@cspell/dict-en_us/-/dict-en_us-4.3.6.tgz#1f554cf4e235af4e8d115c5924c87537b16a08d0" - integrity sha512-odhgsjNZI9BtEOJdvqfAuv/3yz5aB1ngfBNaph7WSnYVt//9e3fhrElZ6/pIIkoyuGgeQPwz1fXt+tMgcnLSEQ== - -"@cspell/dict-filetypes@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@cspell/dict-filetypes/-/dict-filetypes-3.0.1.tgz#61642b14af90894e6acf4c00f20ab2d097c1ed12" - integrity sha512-8z8mY1IbrTyTRumx2vvD9yzRhNMk9SajM/GtI5hdMM2pPpNSp25bnuauzjRf300eqlqPY2MNb5MmhBFO014DJw== - -"@cspell/dict-fonts@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@cspell/dict-fonts/-/dict-fonts-4.0.0.tgz#9bc8beb2a7b068b4fdb45cb994b36fd184316327" - integrity sha512-t9V4GeN/m517UZn63kZPUYP3OQg5f0OBLSd3Md5CU3eH1IFogSvTzHHnz4Wqqbv8NNRiBZ3HfdY/pqREZ6br3Q== - -"@cspell/dict-fsharp@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@cspell/dict-fsharp/-/dict-fsharp-1.0.0.tgz#420df73069f7bb8efe82bf823eef620647a571bc" - integrity sha512-dHPkMHwW4dWv3Lv9VWxHuVm4IylqvcfRBSnZ7usJTRThraetSVrOPIJwr6UJh7F5un/lGJx2lxWVApf2WQaB/A== - -"@cspell/dict-fullstack@^3.1.5": - version "3.1.5" - resolved "https://registry.yarnpkg.com/@cspell/dict-fullstack/-/dict-fullstack-3.1.5.tgz#35d18678161f214575cc613dd95564e05422a19c" - integrity sha512-6ppvo1dkXUZ3fbYn/wwzERxCa76RtDDl5Afzv2lijLoijGGUw5yYdLBKJnx8PJBGNLh829X352ftE7BElG4leA== - -"@cspell/dict-gaming-terms@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@cspell/dict-gaming-terms/-/dict-gaming-terms-1.0.4.tgz#b67d89d014d865da6cb40de4269d4c162a00658e" - integrity sha512-hbDduNXlk4AOY0wFxcDMWBPpm34rpqJBeqaySeoUH70eKxpxm+dvjpoRLJgyu0TmymEICCQSl6lAHTHSDiWKZg== - -"@cspell/dict-git@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@cspell/dict-git/-/dict-git-2.0.0.tgz#fa5cb298845da9c69efc01c6af07a99097718dc9" - integrity sha512-n1AxyX5Kgxij/sZFkxFJlzn3K9y/sCcgVPg/vz4WNJ4K9YeTsUmyGLA2OQI7d10GJeiuAo2AP1iZf2A8j9aj2w== - -"@cspell/dict-golang@^6.0.2": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@cspell/dict-golang/-/dict-golang-6.0.2.tgz#dcba58b9e658c1cc713c19965a358185d15d1987" - integrity sha512-5pyZn4AAiYukAW+gVMIMVmUSkIERFrDX2vtPDjg8PLQUhAHWiVeQSDjuOhq9/C5GCCEZU/zWSONkGiwLBBvV9A== - -"@cspell/dict-haskell@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@cspell/dict-haskell/-/dict-haskell-4.0.1.tgz#e9fca7c452411ff11926e23ffed2b50bb9b95e47" - integrity sha512-uRrl65mGrOmwT7NxspB4xKXFUenNC7IikmpRZW8Uzqbqcu7ZRCUfstuVH7T1rmjRgRkjcIjE4PC11luDou4wEQ== - -"@cspell/dict-html-symbol-entities@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.0.tgz#4d86ac18a4a11fdb61dfb6f5929acd768a52564f" - integrity sha512-HGRu+48ErJjoweR5IbcixxETRewrBb0uxQBd6xFGcxbEYCX8CnQFTAmKI5xNaIt2PKaZiJH3ijodGSqbKdsxhw== - -"@cspell/dict-html@^4.0.3": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@cspell/dict-html/-/dict-html-4.0.3.tgz#155450cb57750774583fce463d01d6323ab41701" - integrity sha512-Gae8i8rrArT0UyG1I6DHDK62b7Be6QEcBSIeWOm4VIIW1CASkN9B0qFgSVnkmfvnu1Y3H7SSaaEynKjdj3cs8w== - -"@cspell/dict-java@^5.0.5": - version "5.0.5" - resolved "https://registry.yarnpkg.com/@cspell/dict-java/-/dict-java-5.0.5.tgz#c673f27ce7a5d96e205f42e8be540aeda0beef11" - integrity sha512-X19AoJgWIBwJBSWGFqSgHaBR/FEykBHTMjL6EqOnhIGEyE9nvuo32tsSHjXNJ230fQxQptEvRZoaldNLtKxsRg== - -"@cspell/dict-k8s@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@cspell/dict-k8s/-/dict-k8s-1.0.1.tgz#6c0cc521dd42fee2c807368ebfef77137686f3a1" - integrity sha512-gc5y4Nm3hVdMZNBZfU2M1AsAmObZsRWjCUk01NFPfGhFBXyVne41T7E62rpnzu5330FV/6b/TnFcPgRmak9lLw== - -"@cspell/dict-latex@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@cspell/dict-latex/-/dict-latex-4.0.0.tgz#85054903db834ea867174795d162e2a8f0e9c51e" - integrity sha512-LPY4y6D5oI7D3d+5JMJHK/wxYTQa2lJMSNxps2JtuF8hbAnBQb3igoWEjEbIbRRH1XBM0X8dQqemnjQNCiAtxQ== - -"@cspell/dict-lorem-ipsum@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-4.0.0.tgz#2793a5dbfde474a546b0caecc40c38fdf076306e" - integrity sha512-1l3yjfNvMzZPibW8A7mQU4kTozwVZVw0AvFEdy+NcqtbxH+TvbSkNMqROOFWrkD2PjnKG0+Ea0tHI2Pi6Gchnw== - -"@cspell/dict-lua@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@cspell/dict-lua/-/dict-lua-4.0.1.tgz#4c31975646cb2d71f1216c7aeaa0c5ab6994ea25" - integrity sha512-j0MFmeCouSoC6EdZTbvGe1sJ9V+ruwKSeF+zRkNNNload7R72Co5kX1haW2xLHGdlq0kqSy1ODRZKdVl0e+7hg== - -"@cspell/dict-node@^4.0.2": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@cspell/dict-node/-/dict-node-4.0.2.tgz#9e5f64d882568fdd2a2243542d1263dbbb87c53a" - integrity sha512-FEQJ4TnMcXEFslqBQkXa5HposMoCGsiBv2ux4IZuIXgadXeHKHUHk60iarWpjhzNzQLyN2GD7NoRMd12bK3Llw== - -"@cspell/dict-npm@^5.0.8": - version "5.0.8" - resolved "https://registry.yarnpkg.com/@cspell/dict-npm/-/dict-npm-5.0.8.tgz#51b2e6dd54f915a2e8725ff7fd75769cb645ff6e" - integrity sha512-KuqH8tEsFD6DPKqKwIfWr9E+admE3yghaC0AKXG8jPaf77N0lkctKaS3dm0oxWUXkYKA/eXj6LCtz3VcTyxFPg== - -"@cspell/dict-php@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@cspell/dict-php/-/dict-php-4.0.1.tgz#f3c5cd241f43a32b09355370fc6ce7bd50e6402c" - integrity sha512-XaQ/JkSyq2c07MfRG54DjLi2CV+HHwS99DDCAao9Fq2JfkWroTQsUeek7wYZXJATrJVOULoV3HKih12x905AtQ== - -"@cspell/dict-powershell@^5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@cspell/dict-powershell/-/dict-powershell-5.0.2.tgz#2b1d7d514354b6d7de405d5faaef30f8eca0ef09" - integrity sha512-IHfWLme3FXE7vnOmMncSBxOsMTdNWd1Vcyhag03WS8oANSgX8IZ+4lMI00mF0ptlgchf16/OU8WsV4pZfikEFw== - -"@cspell/dict-public-licenses@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.3.tgz#fa03649a5d6b8284e0c1da17eb449707df1a2a1c" - integrity sha512-JSLEdpEYufQ1H+93UHi+axlqQm1fhgK6kpdLHp6uPHu//CsvETcqNVawjB+qOdI/g38JTMw5fBqSd0aGNxa6Dw== - -"@cspell/dict-python@^4.1.5": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@cspell/dict-python/-/dict-python-4.1.5.tgz#0c5eab3f12a166c9339dec508d8b07b4dddab1d4" - integrity sha512-wWUWyHdyJtx5iG6Fz9rBQ17BtdpEsB17vmutao+gixQD28Jzb6XoLgDQ6606M0RnFjBSFhs5iT4CJBzlD2Kq6g== - dependencies: - "@cspell/dict-data-science" "^1.0.0" - -"@cspell/dict-r@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@cspell/dict-r/-/dict-r-2.0.1.tgz#73474fb7cce45deb9094ebf61083fbf5913f440a" - integrity sha512-KCmKaeYMLm2Ip79mlYPc8p+B2uzwBp4KMkzeLd5E6jUlCL93Y5Nvq68wV5fRLDRTf7N1LvofkVFWfDcednFOgA== - -"@cspell/dict-ruby@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@cspell/dict-ruby/-/dict-ruby-5.0.0.tgz#ca22ddf0842f29b485e3ef585c666c6be5227e6d" - integrity sha512-ssb96QxLZ76yPqFrikWxItnCbUKhYXJ2owkoIYzUGNFl2CHSoHCb5a6Zetum9mQ/oUA3gNeUhd28ZUlXs0la2A== - -"@cspell/dict-rust@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@cspell/dict-rust/-/dict-rust-4.0.1.tgz#ef0b88cb3a45265824e2c9ce31b0baa4e1050351" - integrity sha512-xJSSzHDK2z6lSVaOmMxl3PTOtfoffaxMo7fTcbZUF+SCJzfKbO6vnN9TCGX2sx1RHFDz66Js6goz6SAZQdOwaw== - -"@cspell/dict-scala@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@cspell/dict-scala/-/dict-scala-5.0.0.tgz#b64365ad559110a36d44ccd90edf7151ea648022" - integrity sha512-ph0twaRoV+ylui022clEO1dZ35QbeEQaKTaV2sPOsdwIokABPIiK09oWwGK9qg7jRGQwVaRPEq0Vp+IG1GpqSQ== - -"@cspell/dict-software-terms@^3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@cspell/dict-software-terms/-/dict-software-terms-3.2.1.tgz#655b52768d05d002d9fc18a0efa63eee66766b8b" - integrity sha512-+QXmyoONVc/3aNgKW+0F0u3XUCRTfNRkWKLZQA78i+9fOfde8ZT4JmROmZgRveH/MxD4n6pNFceIRcYI6C8WuQ== - -"@cspell/dict-sql@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@cspell/dict-sql/-/dict-sql-2.1.1.tgz#eb16c8bece4ff3154a193fe854a600ed0f75c64c" - integrity sha512-v1mswi9NF40+UDUMuI148YQPEQvWjac72P6ZsjlRdLjEiQEEMEsTQ+zlkIdnzC9QCNyJaqD5Liq9Mn78/8Zxtw== - -"@cspell/dict-svelte@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@cspell/dict-svelte/-/dict-svelte-1.0.2.tgz#0c866b08a7a6b33bbc1a3bdbe6a1b484ca15cdaa" - integrity sha512-rPJmnn/GsDs0btNvrRBciOhngKV98yZ9SHmg8qI6HLS8hZKvcXc0LMsf9LLuMK1TmS2+WQFAan6qeqg6bBxL2Q== - -"@cspell/dict-swift@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@cspell/dict-swift/-/dict-swift-2.0.1.tgz#06ec86e52e9630c441d3c19605657457e33d7bb6" - integrity sha512-gxrCMUOndOk7xZFmXNtkCEeroZRnS2VbeaIPiymGRHj5H+qfTAzAKxtv7jJbVA3YYvEzWcVE2oKDP4wcbhIERw== - -"@cspell/dict-typescript@^3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@cspell/dict-typescript/-/dict-typescript-3.1.1.tgz#25a9c241fa79c032f907db21b0aaf7c7baee6cc3" - integrity sha512-N9vNJZoOXmmrFPR4ir3rGvnqqwmQGgOYoL1+y6D4oIhyr7FhaYiyF/d7QT61RmjZQcATMa6PSL+ZisCeRLx9+A== - -"@cspell/dict-vue@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@cspell/dict-vue/-/dict-vue-3.0.0.tgz#68ccb432ad93fcb0fd665352d075ae9a64ea9250" - integrity sha512-niiEMPWPV9IeRBRzZ0TBZmNnkK3olkOPYxC1Ny2AX4TGlYRajcW0WUtoSHmvvjZNfWLSg2L6ruiBeuPSbjnG6A== - -"@cspell/dynamic-import@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@cspell/dynamic-import/-/dynamic-import-7.0.0.tgz#96f4ec55cca88939364abf4f0d51dc981ab959a1" - integrity sha512-GRSJvdQvVOC0y7Qla8eg6LLe8p8WnbnHLabGJGsqYfXgtfkUFev9v65kMybQSJt9qhDtGCRw6EN1UyaeeEtavQ== - dependencies: - import-meta-resolve "^3.0.0" - -"@cspell/strong-weak-map@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@cspell/strong-weak-map/-/strong-weak-map-7.0.0.tgz#a8a4d16c1d5c4a8892465b25685e3ef2c28236f0" - integrity sha512-DT1R30i3V7aJIGLt7x1igaMLHhYSFv6pgc9gNwXvZWFl1xm/f7Jx07GPXKKKhwwXd4vy7G5rhwo63F4Pt9i8Ng== - -"@cspotcode/source-map-support@^0.8.0": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== - dependencies: - "@jridgewell/trace-mapping" "0.3.9" - -"@esbuild-kit/cjs-loader@^2.4.2": - version "2.4.2" - resolved "https://registry.yarnpkg.com/@esbuild-kit/cjs-loader/-/cjs-loader-2.4.2.tgz#cb4dde00fbf744a68c4f20162ea15a8242d0fa54" - integrity sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg== - dependencies: - "@esbuild-kit/core-utils" "^3.0.0" - get-tsconfig "^4.4.0" - -"@esbuild-kit/core-utils@^3.0.0", "@esbuild-kit/core-utils@^3.2.2": - version "3.2.2" - resolved "https://registry.yarnpkg.com/@esbuild-kit/core-utils/-/core-utils-3.2.2.tgz#ac3fe38d6ddcb3aa4658425034bb7a9cefa83495" - integrity sha512-Ub6LaRaAgF80dTSzUdXpFLM1pVDdmEVB9qb5iAzSpyDlX/mfJTFGOnZ516O05p5uWWteNviMKi4PAyEuRxI5gA== - dependencies: - esbuild "~0.18.20" - source-map-support "^0.5.21" - -"@esbuild-kit/esm-loader@^2.5.5": - version "2.5.5" - resolved "https://registry.yarnpkg.com/@esbuild-kit/esm-loader/-/esm-loader-2.5.5.tgz#b82da14fcee3fc1d219869756c06f43f67d1ca71" - integrity sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw== - dependencies: - "@esbuild-kit/core-utils" "^3.0.0" - get-tsconfig "^4.4.0" - -"@esbuild/android-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" - integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== - -"@esbuild/android-arm@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" - integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== - -"@esbuild/android-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" - integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== - -"@esbuild/darwin-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" - integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== - -"@esbuild/darwin-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" - integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== - -"@esbuild/freebsd-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" - integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== - -"@esbuild/freebsd-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" - integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== - -"@esbuild/linux-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" - integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== - -"@esbuild/linux-arm@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" - integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== - -"@esbuild/linux-ia32@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" - integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== - -"@esbuild/linux-loong64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" - integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== - -"@esbuild/linux-mips64el@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" - integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== - -"@esbuild/linux-ppc64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" - integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== - -"@esbuild/linux-riscv64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" - integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== - -"@esbuild/linux-s390x@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" - integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== - -"@esbuild/linux-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" - integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== - -"@esbuild/netbsd-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" - integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== - -"@esbuild/openbsd-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" - integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== - -"@esbuild/sunos-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" - integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== - -"@esbuild/win32-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" - integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== - -"@esbuild/win32-ia32@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" - integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== - -"@esbuild/win32-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" - integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== - -"@eslint-community/eslint-utils@^4.2.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" - integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== - dependencies: - eslint-visitor-keys "^3.3.0" - -"@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.1": - version "4.8.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.0.tgz#11195513186f68d42fbf449f9a7136b2c0c92005" - integrity sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg== - -"@eslint/eslintrc@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" - integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.6.0" - globals "^13.19.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" - strip-json-comments "^3.1.1" - -"@eslint/js@8.49.0": - version "8.49.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.49.0.tgz#86f79756004a97fa4df866835093f1df3d03c333" - integrity sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w== - -"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" - integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== - dependencies: - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" - integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - -"@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" - integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - -"@ethersproject/address@5.7.0", "@ethersproject/address@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" - integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - -"@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" - integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== - dependencies: - "@ethersproject/bytes" "^5.7.0" - -"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" - integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - -"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" - integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - bn.js "^5.2.1" - -"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" - integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== - dependencies: - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" - integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - -"@ethersproject/contracts@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" - integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== - dependencies: - "@ethersproject/abi" "^5.7.0" - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - -"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" - integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" - integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/pbkdf2" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/wordlists" "^5.7.0" - -"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" - integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hdnode" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/pbkdf2" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - aes-js "3.0.0" - scrypt-js "3.0.1" - -"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" - integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== - dependencies: - "@ethersproject/bytes" "^5.7.0" - js-sha3 "0.8.0" - -"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" - integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== - -"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": - version "5.7.1" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" - integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== - dependencies: - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" - integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - -"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" - integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== - dependencies: - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/providers@5.7.2": - version "5.7.2" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" - integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - bech32 "1.1.4" - ws "7.4.6" - -"@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" - integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" - integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" - integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - hash.js "1.1.7" - -"@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" - integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - bn.js "^5.2.1" - elliptic "6.5.4" - hash.js "1.1.7" - -"@ethersproject/solidity@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8" - integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" - integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" - integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== - dependencies: - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - -"@ethersproject/units@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" - integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/wallet@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" - integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/hdnode" "^5.7.0" - "@ethersproject/json-wallets" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/wordlists" "^5.7.0" - -"@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": - version "5.7.1" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" - integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== - dependencies: - "@ethersproject/base64" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" - integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@hapi/bourne@^2.0.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-2.1.0.tgz#66aff77094dc3080bd5df44ec63881f2676eb020" - integrity sha512-i1BpaNDVLJdRBEKeJWkVO6tYX6DMFBuwMhSuWqLsY4ufeTKGVuV5rBsUhxPayXqnnWHgXUAmWK16H/ykO5Wj4Q== - -"@humanwhocodes/config-array@^0.11.11": - version "0.11.11" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" - integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== - dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" - minimatch "^3.0.5" - -"@humanwhocodes/module-importer@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" - integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== - -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== - -"@istanbuljs/load-nyc-config@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" - integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== - dependencies: - camelcase "^5.3.1" - find-up "^4.1.0" - get-package-type "^0.1.0" - js-yaml "^3.13.1" - resolve-from "^5.0.0" - -"@istanbuljs/schema@^0.1.2": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" - integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== - -"@jest/console@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" - integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== - dependencies: - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^26.6.2" - jest-util "^26.6.2" - slash "^3.0.0" - -"@jest/core@^26.6.3": - version "26.6.3" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" - integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== - dependencies: - "@jest/console" "^26.6.2" - "@jest/reporters" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.4" - jest-changed-files "^26.6.2" - jest-config "^26.6.3" - jest-haste-map "^26.6.2" - jest-message-util "^26.6.2" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-resolve-dependencies "^26.6.3" - jest-runner "^26.6.3" - jest-runtime "^26.6.3" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" - jest-watcher "^26.6.2" - micromatch "^4.0.2" - p-each-series "^2.1.0" - rimraf "^3.0.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - -"@jest/environment@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" - integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== - dependencies: - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - jest-mock "^26.6.2" - -"@jest/expect-utils@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-28.1.3.tgz#58561ce5db7cd253a7edddbc051fb39dda50f525" - integrity sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA== - dependencies: - jest-get-type "^28.0.2" - -"@jest/fake-timers@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" - integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== - dependencies: - "@jest/types" "^26.6.2" - "@sinonjs/fake-timers" "^6.0.1" - "@types/node" "*" - jest-message-util "^26.6.2" - jest-mock "^26.6.2" - jest-util "^26.6.2" - -"@jest/globals@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" - integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== - dependencies: - "@jest/environment" "^26.6.2" - "@jest/types" "^26.6.2" - expect "^26.6.2" - -"@jest/reporters@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" - integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - chalk "^4.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.2" - graceful-fs "^4.2.4" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^4.0.3" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.0.2" - jest-haste-map "^26.6.2" - jest-resolve "^26.6.2" - jest-util "^26.6.2" - jest-worker "^26.6.2" - slash "^3.0.0" - source-map "^0.6.0" - string-length "^4.0.1" - terminal-link "^2.0.0" - v8-to-istanbul "^7.0.0" - optionalDependencies: - node-notifier "^8.0.0" - -"@jest/schemas@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-28.1.3.tgz#ad8b86a66f11f33619e3d7e1dcddd7f2d40ff905" - integrity sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg== - dependencies: - "@sinclair/typebox" "^0.24.1" - -"@jest/source-map@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" - integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== - dependencies: - callsites "^3.0.0" - graceful-fs "^4.2.4" - source-map "^0.6.0" - -"@jest/test-result@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" - integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== - dependencies: - "@jest/console" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - -"@jest/test-sequencer@^26.6.3": - version "26.6.3" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" - integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== - dependencies: - "@jest/test-result" "^26.6.2" - graceful-fs "^4.2.4" - jest-haste-map "^26.6.2" - jest-runner "^26.6.3" - jest-runtime "^26.6.3" - -"@jest/transform@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" - integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^26.6.2" - babel-plugin-istanbul "^6.0.0" - chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.4" - jest-haste-map "^26.6.2" - jest-regex-util "^26.0.0" - jest-util "^26.6.2" - micromatch "^4.0.2" - pirates "^4.0.1" - slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" - -"@jest/types@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" - integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - -"@jest/types@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-28.1.3.tgz#b05de80996ff12512bc5ceb1d208285a7d11748b" - integrity sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ== - dependencies: - "@jest/schemas" "^28.1.3" - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^17.0.8" - chalk "^4.0.0" - -"@jimp/bmp@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/bmp/-/bmp-0.22.10.tgz#e4fe8934a83f1e677cbfd74ad22a684bf1aad529" - integrity sha512-1UXRl1Nw1KptZ1r0ANqtXOst9vGH51dq7keVKQzyyTO2lz4dOaezS9StuSTNh+RmiHg/SVPaFRpPfB0S/ln4Kg== - dependencies: - "@jimp/utils" "^0.22.10" - bmp-js "^0.1.0" - -"@jimp/core@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/core/-/core-0.22.10.tgz#a106e719a9e1bc668c9595065a0872767cda3934" - integrity sha512-ZKyrehVy6wu1PnBXIUpn/fXmyMRQiVSbvHDubgXz4bfTOao3GiOurKHjByutQIgozuAN6ZHWiSge1dKA+dex3w== - dependencies: - "@jimp/utils" "^0.22.10" - any-base "^1.1.0" - buffer "^5.2.0" - exif-parser "^0.1.12" - file-type "^16.5.4" - isomorphic-fetch "^3.0.0" - pixelmatch "^4.0.2" - tinycolor2 "^1.6.0" - -"@jimp/custom@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/custom/-/custom-0.22.10.tgz#621f3ec418c59c78ca43c5bc6f91a467e48a7a87" - integrity sha512-sPZkUYe1hu0iIgNisjizxPJqq2vaaKvkCkPoXq2U6UV3ZA1si/WVdrg25da3IcGIEV+83AoHgM8TvqlLgrCJsg== - dependencies: - "@jimp/core" "^0.22.10" - -"@jimp/gif@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/gif/-/gif-0.22.10.tgz#fc47738edc5f5327a0c023ad40e89417fdb5ef60" - integrity sha512-yEX2dSpamvkSx1PPDWGnKeWDrBz0vrCKjVG/cn4Zr68MRRT75tbZIeOrBa+RiUpY3ho5ix7d36LkYvt3qfUIhQ== - dependencies: - "@jimp/utils" "^0.22.10" - gifwrap "^0.10.1" - omggif "^1.0.9" - -"@jimp/jpeg@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/jpeg/-/jpeg-0.22.10.tgz#b4aba85d607d598d5a4ce0c66cefe69a8fc45c26" - integrity sha512-6bu98pAcVN4DY2oiDLC4TOgieX/lZrLd1tombWZOFCN5PBmqaHQxm7IUmT+Wj4faEvh8QSHgVLSA+2JQQRJWVA== - dependencies: - "@jimp/utils" "^0.22.10" - jpeg-js "^0.4.4" - -"@jimp/plugin-blit@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-blit/-/plugin-blit-0.22.10.tgz#c351a27d52d8273b61d4f3cd68a9b73b03dd7b14" - integrity sha512-6EI8Sl+mxYHEIy6Yteh6eknD+EZguKpNdr3sCKxNezmLR0+vK99vHcllo6uGSjXXiwtwS67Xqxn8SsoatL+UJQ== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-blur@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-blur/-/plugin-blur-0.22.10.tgz#22a67bb8b21403ac28b44bef6cf9a934846fec83" - integrity sha512-4XRTWuPVdMXJeclJMisXPGizeHtTryVaVV5HnuQXpKqIZtzXReCCpNGH8q/i0kBQOQMXhGWS3mpqOEwtpPePKw== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-circle@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-circle/-/plugin-circle-0.22.10.tgz#2a4c81b5c1a49f583d2d5090496c1ecb29c52c1a" - integrity sha512-mhcwTO1ywRxiCgtLGge6tDDIDPlX6qkI3CY+BjgGG/XhVHccCddXgOGLdlf+5OuKIEF2Nqs0V01LQEQIJFTmEw== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-color@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-color/-/plugin-color-0.22.10.tgz#cf053aa30eb3bf7df3cceb8547ef78a841bfcd72" - integrity sha512-e4t3L7Kedd96E0x1XjsTM6NcgulKUU66HdFTao7Tc9FYJRFSlttARZ/C6LEryGDm/i69R6bJEpo7BkNz0YL55Q== - dependencies: - "@jimp/utils" "^0.22.10" - tinycolor2 "^1.6.0" - -"@jimp/plugin-contain@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-contain/-/plugin-contain-0.22.10.tgz#5302e088a09884ff0ae6656e0e682e2e487c2199" - integrity sha512-eP8KrzctuEoqibQAxi9WhbnoRosydhiwg+IYya3dKuKDBTrD9UHt+ERlPQ/lTNWHzV/l4S1ntV3r9s9saJgsXA== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-cover@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-cover/-/plugin-cover-0.22.10.tgz#746b25bbea92aa7f9b130feca5af02717122e6d5" - integrity sha512-kJCwL5T1igfa0InCfkE7bBeqg26m46aoRt10ug+rvm11P6RrvRMGrgINFyIKB+mnB7CiyBN/MOula1CvLhSInQ== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-crop@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-crop/-/plugin-crop-0.22.10.tgz#6204fd6be751d7edb64a86ab788ba762843b9877" - integrity sha512-BOZ+YGaZlhU7c5ye65RxikicXH0Ki0It6/XHISvipR5WZrfjLjL2Ke20G+AGnwBQc76gKenVcMXVUCnEjtZV+Q== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-displace@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-displace/-/plugin-displace-0.22.10.tgz#6dc277c84c0c6b2c2d793271ddf45b61284cb043" - integrity sha512-llNiWWMTKISDXt5+cXI0GaFmZWAjlT+4fFLYf4eXquuL/9wZoQsEBhv2GdGd48mkiS8jZq1Nnb2Q4ehEPTvrzw== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-dither@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-dither/-/plugin-dither-0.22.10.tgz#9cbad07fb16d2dcb88d86c16d5437dee9232426a" - integrity sha512-05WLmeV5M+P/0FS+bWf13hMew2X0oa8w9AtmevL2UyA/5GqiyvP2Xm5WfGQ8oFiiMvpnL6RFomJQOZtWca0C2w== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-fisheye@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-fisheye/-/plugin-fisheye-0.22.10.tgz#94cbb32947d24cdd596f7259754e390e69c3e7a6" - integrity sha512-InjiXvc7Gkzrx8VWtU97kDqV7ENnhHGPULymJWeZaF2aicud9Fpk4iCtd/DcZIrk7Cbe60A8RwNXN00HXIbSCg== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-flip@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-flip/-/plugin-flip-0.22.10.tgz#58f9e05c5038d1ab849bda41cee4f0416fe07fb5" - integrity sha512-42GkGtTHWnhnwTMPVK/kXObZbkYIpQWfuIfy5EMEMk6zRj05zpv4vsjkKWfuemweZINwfvD7wDJF7FVFNNcZZg== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-gaussian@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-gaussian/-/plugin-gaussian-0.22.10.tgz#69effed5dccd11eada36262bd65fbaa06bd8be84" - integrity sha512-ykrG/6lTp9Q5YA8jS5XzwMHtRxb9HOFMgtmnrUZ8kU+BK8REecfy9Ic5BUEOjCYvS1a/xLsnrZQU07iiYxBxFg== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-invert@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-invert/-/plugin-invert-0.22.10.tgz#370b4ce4634b3e2c5fbbe88270a74f5673c765bb" - integrity sha512-d8j9BlUJYs/c994t4azUWSWmQq4LLPG4ecm8m6SSNqap+S/HlVQGqjYhJEBbY9EXkOTYB9vBL9bqwSM1Rr6paA== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-mask@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-mask/-/plugin-mask-0.22.10.tgz#6404f54a782c952fecf7b6ae0f3d894d4fc99c51" - integrity sha512-yRBs1230XZkz24uFTdTcSlZ0HXZpIWzM3iFQN56MzZ7USgdVZjPPDCQ8I9RpqfZ36nDflQkUO0wV7ucsi4ogow== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-normalize@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-normalize/-/plugin-normalize-0.22.10.tgz#6a8d0f57a8f90a3ec15f2391c338b94f3eb49e72" - integrity sha512-Wk9GX6eJMchX/ZAazVa70Fagu+OXMvHiPY+HrcEwcclL+p1wo8xAHEsf9iKno7Ja4EU9lLhbBRY5hYJyiKMEkg== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-print@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-print/-/plugin-print-0.22.10.tgz#8c96df70851c1ead0b79c8ea74c8411445d921ca" - integrity sha512-1U3VloIR+beE1kWPdGEJMiE2h1Do29iv3w8sBbvPyRP4qXxRFcDpmCGtctsrKmb1krlBFlj8ubyAY90xL+5n9w== - dependencies: - "@jimp/utils" "^0.22.10" - load-bmfont "^1.4.1" - -"@jimp/plugin-resize@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-resize/-/plugin-resize-0.22.10.tgz#d968f0167069c9f7e612bceefdbcc4b3c65934b5" - integrity sha512-ixomxVcnAONXDgaq0opvAx4UAOiEhOA/tipuhFFOvPKFd4yf1BAnEviB5maB0SBHHkJXPUSzDp/73xVTMGSe7g== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-rotate@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-rotate/-/plugin-rotate-0.22.10.tgz#93d3781eca02d549a632db74bc63d27a6bb9a38c" - integrity sha512-eeFX8dnRyf3LAdsdXWKWuN18hLRg8zy1cP0cP9rHzQVWRK7ck/QsLxK1vHq7MADGwQalNaNTJ9SQxH6c8mz6jw== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-scale@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-scale/-/plugin-scale-0.22.10.tgz#69127d45eb0837cd23cd04cff3677344064670ac" - integrity sha512-TG/H0oUN69C9ArBCZg4PmuoixFVKIiru8282KzSB/Tp1I0xwX0XLTv3dJ5pobPlIgPcB+TmD4xAIdkCT4rtWxg== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-shadow@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-shadow/-/plugin-shadow-0.22.10.tgz#ccf379a8d41861eb07c35a60f3dcdede8e856de7" - integrity sha512-TN9xm6fI7XfxbMUQqFPZjv59Xdpf0tSiAQdINB4g6pJMWiVANR/74OtDONoy3KKpenu5Y38s+FkrtID/KcQAhw== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugin-threshold@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugin-threshold/-/plugin-threshold-0.22.10.tgz#590bda5ddf9071adad36f98197e710f33cb47a26" - integrity sha512-DA2lSnU0TgIRbAgmXaxroYw3Ad6J2DOFEoJp0NleSm2h3GWbZEE5yW9U2B6hD3iqn4AenG4E2b2WzHXZyzSutw== - dependencies: - "@jimp/utils" "^0.22.10" - -"@jimp/plugins@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/plugins/-/plugins-0.22.10.tgz#7062b6a36dc2d9c8dbd574a7697b6efaccecdee8" - integrity sha512-KDMZyM6pmvS8freB+UBLko1TO/k4D7URS/nphCozuH+P7i3UMe7NdckXKJ8u+WD6sqN0YFYvBehpkpnUiw/91w== - dependencies: - "@jimp/plugin-blit" "^0.22.10" - "@jimp/plugin-blur" "^0.22.10" - "@jimp/plugin-circle" "^0.22.10" - "@jimp/plugin-color" "^0.22.10" - "@jimp/plugin-contain" "^0.22.10" - "@jimp/plugin-cover" "^0.22.10" - "@jimp/plugin-crop" "^0.22.10" - "@jimp/plugin-displace" "^0.22.10" - "@jimp/plugin-dither" "^0.22.10" - "@jimp/plugin-fisheye" "^0.22.10" - "@jimp/plugin-flip" "^0.22.10" - "@jimp/plugin-gaussian" "^0.22.10" - "@jimp/plugin-invert" "^0.22.10" - "@jimp/plugin-mask" "^0.22.10" - "@jimp/plugin-normalize" "^0.22.10" - "@jimp/plugin-print" "^0.22.10" - "@jimp/plugin-resize" "^0.22.10" - "@jimp/plugin-rotate" "^0.22.10" - "@jimp/plugin-scale" "^0.22.10" - "@jimp/plugin-shadow" "^0.22.10" - "@jimp/plugin-threshold" "^0.22.10" - timm "^1.6.1" - -"@jimp/png@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/png/-/png-0.22.10.tgz#397da6479f515dc87525b0f25efe4cb11cb75156" - integrity sha512-RYinU7tZToeeR2g2qAMn42AU+8OUHjXPKZZ9RkmoL4bguA1xyZWaSdr22/FBkmnHhOERRlr02KPDN1OTOYHLDQ== - dependencies: - "@jimp/utils" "^0.22.10" - pngjs "^6.0.0" - -"@jimp/tiff@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/tiff/-/tiff-0.22.10.tgz#e5511e21c73719a308545732f1ec050f52a8e0ad" - integrity sha512-OaivlSYzpNTHyH/h7pEtl3A7F7TbsgytZs52GLX/xITW92ffgDgT6PkldIrMrET6ERh/hdijNQiew7IoEEr2og== - dependencies: - utif2 "^4.0.1" - -"@jimp/types@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/types/-/types-0.22.10.tgz#1ae01dfea9f36ba9751e63a1eedecb4c4da9ef16" - integrity sha512-u/r+XYzbCx4zZukDmxx8S0er3Yq3iDPI6+31WKX0N18i2qPPJYcn8qwIFurfupRumGvJ8SlGLCgt/T+Y8zzUIw== - dependencies: - "@jimp/bmp" "^0.22.10" - "@jimp/gif" "^0.22.10" - "@jimp/jpeg" "^0.22.10" - "@jimp/png" "^0.22.10" - "@jimp/tiff" "^0.22.10" - timm "^1.6.1" - -"@jimp/utils@^0.22.10": - version "0.22.10" - resolved "https://registry.yarnpkg.com/@jimp/utils/-/utils-0.22.10.tgz#d05934fae1c4bd988205d3decc2a649df0724a26" - integrity sha512-ztlOK9Mm2iLG2AMoabzM4i3WZ/FtshcgsJCbZCRUs/DKoeS2tySRJTnQZ1b7Roq0M4Ce+FUAxnCAcBV0q7PH9w== - dependencies: - regenerator-runtime "^0.13.3" - -"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" - integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" - integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== - -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.19" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" - integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@netlify/functions@^1.4.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@netlify/functions/-/functions-1.6.0.tgz#c373423e6fef0e6f7422ac0345e8bbf2cb692366" - integrity sha512-6G92AlcpFrQG72XU8YH8pg94eDnq7+Q0YJhb8x4qNpdGsvuzvrfHWBmqFGp/Yshmv4wex9lpsTRZOocdrA2erQ== - dependencies: - is-promise "^4.0.0" - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@octokit/auth-app@^4.0.2": - version "4.0.13" - resolved "https://registry.yarnpkg.com/@octokit/auth-app/-/auth-app-4.0.13.tgz#53323bee6bfefbb73ea544dd8e6a0144550e13e3" - integrity sha512-NBQkmR/Zsc+8fWcVIFrwDgNXS7f4XDrkd9LHdi9DPQw1NdGHLviLzRO2ZBwTtepnwHXW5VTrVU9eFGijMUqllg== - dependencies: - "@octokit/auth-oauth-app" "^5.0.0" - "@octokit/auth-oauth-user" "^2.0.0" - "@octokit/request" "^6.0.0" - "@octokit/request-error" "^3.0.0" - "@octokit/types" "^9.0.0" - deprecation "^2.3.1" - lru-cache "^9.0.0" - universal-github-app-jwt "^1.1.1" - universal-user-agent "^6.0.0" - -"@octokit/auth-oauth-app@^5.0.0": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-app/-/auth-oauth-app-5.0.6.tgz#e5f922623eb261485efc87f5d0d5b509c71caec8" - integrity sha512-SxyfIBfeFcWd9Z/m1xa4LENTQ3l1y6Nrg31k2Dcb1jS5ov7pmwMJZ6OGX8q3K9slRgVpeAjNA1ipOAMHkieqyw== - dependencies: - "@octokit/auth-oauth-device" "^4.0.0" - "@octokit/auth-oauth-user" "^2.0.0" - "@octokit/request" "^6.0.0" - "@octokit/types" "^9.0.0" - "@types/btoa-lite" "^1.0.0" - btoa-lite "^1.0.0" - universal-user-agent "^6.0.0" - -"@octokit/auth-oauth-device@^4.0.0": - version "4.0.5" - resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-device/-/auth-oauth-device-4.0.5.tgz#21e981f51ae63d419ca3db0b75e32c85b33fa0da" - integrity sha512-XyhoWRTzf2ZX0aZ52a6Ew5S5VBAfwwx1QnC2Np6Et3MWQpZjlREIcbcvVZtkNuXp6Z9EeiSLSDUqm3C+aMEHzQ== - dependencies: - "@octokit/oauth-methods" "^2.0.0" - "@octokit/request" "^6.0.0" - "@octokit/types" "^9.0.0" - universal-user-agent "^6.0.0" - -"@octokit/auth-oauth-user@^2.0.0": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-user/-/auth-oauth-user-2.1.2.tgz#7091e1b29527e577b16d0f1699d49fe3d39946ff" - integrity sha512-kkRqNmFe7s5GQcojE3nSlF+AzYPpPv7kvP/xYEnE57584pixaFBH8Vovt+w5Y3E4zWUEOxjdLItmBTFAWECPAg== - dependencies: - "@octokit/auth-oauth-device" "^4.0.0" - "@octokit/oauth-methods" "^2.0.0" - "@octokit/request" "^6.0.0" - "@octokit/types" "^9.0.0" - btoa-lite "^1.0.0" - universal-user-agent "^6.0.0" - -"@octokit/auth-token@^2.4.4": - version "2.5.0" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36" - integrity sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g== - dependencies: - "@octokit/types" "^6.0.3" - -"@octokit/auth-token@^3.0.0": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-3.0.4.tgz#70e941ba742bdd2b49bdb7393e821dea8520a3db" - integrity sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ== - -"@octokit/auth-unauthenticated@^3.0.0": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@octokit/auth-unauthenticated/-/auth-unauthenticated-3.0.5.tgz#a562bffd6ca0d0e80541eaf9f9b89b8d53020228" - integrity sha512-yH2GPFcjrTvDWPwJWWCh0tPPtTL5SMgivgKPA+6v/XmYN6hGQkAto8JtZibSKOpf8ipmeYhLNWQ2UgW0GYILCw== - dependencies: - "@octokit/request-error" "^3.0.0" - "@octokit/types" "^9.0.0" - -"@octokit/core@^3.2.4": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.6.0.tgz#3376cb9f3008d9b3d110370d90e0a1fcd5fe6085" - integrity sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q== - dependencies: - "@octokit/auth-token" "^2.4.4" - "@octokit/graphql" "^4.5.8" - "@octokit/request" "^5.6.3" - "@octokit/request-error" "^2.0.5" - "@octokit/types" "^6.0.3" - before-after-hook "^2.2.0" - universal-user-agent "^6.0.0" - -"@octokit/endpoint@^6.0.1": - version "6.0.12" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" - integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA== - dependencies: - "@octokit/types" "^6.0.3" - is-plain-object "^5.0.0" - universal-user-agent "^6.0.0" - -"@octokit/endpoint@^7.0.0": - version "7.0.6" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-7.0.6.tgz#791f65d3937555141fb6c08f91d618a7d645f1e2" - integrity sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg== - dependencies: - "@octokit/types" "^9.0.0" - is-plain-object "^5.0.0" - universal-user-agent "^6.0.0" - -"@octokit/graphql@^4.5.8": - version "4.8.0" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3" - integrity sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg== - dependencies: - "@octokit/request" "^5.6.0" - "@octokit/types" "^6.0.3" - universal-user-agent "^6.0.0" - -"@octokit/oauth-authorization-url@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@octokit/oauth-authorization-url/-/oauth-authorization-url-5.0.0.tgz#029626ce87f3b31addb98cd0d2355c2381a1c5a1" - integrity sha512-y1WhN+ERDZTh0qZ4SR+zotgsQUE1ysKnvBt1hvDRB2WRzYtVKQjn97HEPzoehh66Fj9LwNdlZh+p6TJatT0zzg== - -"@octokit/oauth-methods@^2.0.0": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@octokit/oauth-methods/-/oauth-methods-2.0.6.tgz#3a089781e90171cbe8a0efa448a6a60229bdd3fb" - integrity sha512-l9Uml2iGN2aTWLZcm8hV+neBiFXAQ9+3sKiQe/sgumHlL6HDg0AQ8/l16xX/5jJvfxueqTW5CWbzd0MjnlfHZw== - dependencies: - "@octokit/oauth-authorization-url" "^5.0.0" - "@octokit/request" "^6.2.3" - "@octokit/request-error" "^3.0.3" - "@octokit/types" "^9.0.0" - btoa-lite "^1.0.0" - -"@octokit/openapi-types@^12.11.0": - version "12.11.0" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-12.11.0.tgz#da5638d64f2b919bca89ce6602d059f1b52d3ef0" - integrity sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ== - -"@octokit/openapi-types@^14.0.0": - version "14.0.0" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-14.0.0.tgz#949c5019028c93f189abbc2fb42f333290f7134a" - integrity sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw== - -"@octokit/openapi-types@^18.0.0": - version "18.0.0" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-18.0.0.tgz#f43d765b3c7533fd6fb88f3f25df079c24fccf69" - integrity sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw== - -"@octokit/plugin-enterprise-compatibility@^1.2.8": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-enterprise-compatibility/-/plugin-enterprise-compatibility-1.3.0.tgz#034f035cc1789b0f0d616e71e41f50f73804e89e" - integrity sha512-h34sMGdEOER/OKrZJ55v26ntdHb9OPfR1fwOx6Q4qYyyhWA104o11h9tFxnS/l41gED6WEI41Vu2G2zHDVC5lQ== - dependencies: - "@octokit/request-error" "^2.1.0" - "@octokit/types" "^6.0.3" - -"@octokit/plugin-paginate-rest@^2.6.2": - version "2.21.3" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz#7f12532797775640dbb8224da577da7dc210c87e" - integrity sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw== - dependencies: - "@octokit/types" "^6.40.0" - -"@octokit/plugin-rest-endpoint-methods@^5.0.1": - version "5.16.2" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz#7ee8bf586df97dd6868cf68f641354e908c25342" - integrity sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw== - dependencies: - "@octokit/types" "^6.39.0" - deprecation "^2.3.1" - -"@octokit/plugin-retry@^3.0.6": - version "3.0.9" - resolved "https://registry.yarnpkg.com/@octokit/plugin-retry/-/plugin-retry-3.0.9.tgz#ae625cca1e42b0253049102acd71c1d5134788fe" - integrity sha512-r+fArdP5+TG6l1Rv/C9hVoty6tldw6cE2pRHNGmFPdyfrc696R6JjrQ3d7HdVqGwuzfyrcaLAKD7K8TX8aehUQ== - dependencies: - "@octokit/types" "^6.0.3" - bottleneck "^2.15.3" - -"@octokit/plugin-throttling@^3.3.4": - version "3.7.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-throttling/-/plugin-throttling-3.7.0.tgz#a35cd05de22b2ef13fde45390d983ff8365b9a9e" - integrity sha512-qrKT1Yl/KuwGSC6/oHpLBot3ooC9rq0/ryDYBCpkRtoj+R8T47xTMDT6Tk2CxWopFota/8Pi/2SqArqwC0JPow== - dependencies: - "@octokit/types" "^6.0.1" - bottleneck "^2.15.3" - -"@octokit/request-error@^2.0.2", "@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677" - integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg== - dependencies: - "@octokit/types" "^6.0.3" - deprecation "^2.0.0" - once "^1.4.0" - -"@octokit/request-error@^3.0.0", "@octokit/request-error@^3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-3.0.3.tgz#ef3dd08b8e964e53e55d471acfe00baa892b9c69" - integrity sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ== - dependencies: - "@octokit/types" "^9.0.0" - deprecation "^2.0.0" - once "^1.4.0" - -"@octokit/request@^5.6.0", "@octokit/request@^5.6.3": - version "5.6.3" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.3.tgz#19a022515a5bba965ac06c9d1334514eb50c48b0" - integrity sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A== - dependencies: - "@octokit/endpoint" "^6.0.1" - "@octokit/request-error" "^2.1.0" - "@octokit/types" "^6.16.1" - is-plain-object "^5.0.0" - node-fetch "^2.6.7" - universal-user-agent "^6.0.0" - -"@octokit/request@^6.0.0", "@octokit/request@^6.2.3": - version "6.2.8" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-6.2.8.tgz#aaf480b32ab2b210e9dadd8271d187c93171d8eb" - integrity sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw== - dependencies: - "@octokit/endpoint" "^7.0.0" - "@octokit/request-error" "^3.0.0" - "@octokit/types" "^9.0.0" - is-plain-object "^5.0.0" - node-fetch "^2.6.7" - universal-user-agent "^6.0.0" - -"@octokit/types@^6.0.1", "@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.39.0", "@octokit/types@^6.40.0": - version "6.41.0" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.41.0.tgz#e58ef78d78596d2fb7df9c6259802464b5f84a04" - integrity sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg== - dependencies: - "@octokit/openapi-types" "^12.11.0" - -"@octokit/types@^8.0.0": - version "8.2.1" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-8.2.1.tgz#a6de091ae68b5541f8d4fcf9a12e32836d4648aa" - integrity sha512-8oWMUji8be66q2B9PmEIUyQm00VPDPun07umUWSaCwxmeaquFBro4Hcc3ruVoDo3zkQyZBlRvhIMEYS3pBhanw== - dependencies: - "@octokit/openapi-types" "^14.0.0" - -"@octokit/types@^9.0.0": - version "9.3.2" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-9.3.2.tgz#3f5f89903b69f6a2d196d78ec35f888c0013cac5" - integrity sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA== - dependencies: - "@octokit/openapi-types" "^18.0.0" - -"@octokit/webhooks-methods@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@octokit/webhooks-methods/-/webhooks-methods-2.0.0.tgz#1108b9ea661ca6c81e4a8bfa63a09eb27d5bc2db" - integrity sha512-35cfQ4YWlnZnmZKmIxlGPUPLtbkF8lr/A/1Sk1eC0ddLMwQN06dOuLc+dI3YLQS+T+MoNt3DIQ0NynwgKPilig== - -"@octokit/webhooks-types@5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@octokit/webhooks-types/-/webhooks-types-5.8.0.tgz#b76d1a3e3ad82cec5680d3c6c3443a620047a6ef" - integrity sha512-8adktjIb76A7viIdayQSFuBEwOzwhDC+9yxZpKNHjfzrlostHCw0/N7JWpWMObfElwvJMk2fY2l1noENCk9wmw== - -"@octokit/webhooks@^9.8.4": - version "9.26.0" - resolved "https://registry.yarnpkg.com/@octokit/webhooks/-/webhooks-9.26.0.tgz#cf453bb313da3b66f1a90c84464d978e1c625cce" - integrity sha512-foZlsgrTDwAmD5j2Czn6ji10lbWjGDVsUxTIydjG9KTkAWKJrFapXJgO5SbGxRwfPd3OJdhK3nA2YPqVhxLXqA== - dependencies: - "@octokit/request-error" "^2.0.2" - "@octokit/webhooks-methods" "^2.0.0" - "@octokit/webhooks-types" "5.8.0" - aggregate-error "^3.1.0" - -"@probot/adapter-aws-lambda-serverless@^3.0.2": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@probot/adapter-aws-lambda-serverless/-/adapter-aws-lambda-serverless-3.0.3.tgz#e841201ba9d8bb408cc578c423422a3a5b8bf32f" - integrity sha512-zYx4pavXqxHj3ohILX2NeAcVF2eO0qmZ79/eBabSMqna+tixrlV8W6oUKkSvuyRQs5fZQjjw79ZhvK40GwhuhA== - dependencies: - "@probot/get-private-key" "^1.1.0" - "@types/aws-lambda" "^8.10.85" - lowercase-keys "^2.0.0" - probot "^12.1.1" - -"@probot/adapter-github-actions@^3.1.3": - version "3.1.3" - resolved "https://registry.yarnpkg.com/@probot/adapter-github-actions/-/adapter-github-actions-3.1.3.tgz#133024a50b91d6ffe8d54623dc51a945b450c5aa" - integrity sha512-mQ0YZrurH1Xvo+2KxZBi2eE8vwywoPveg370aIxY22g47xP5lpGR46ahL4TChZN5RpL82Rp7wEl8+Ue2PUrZsw== - dependencies: - "@actions/core" "^1.2.6" - pino "^8.5.0" - probot "^12.2.1" - through2 "^4.0.2" - -"@probot/get-private-key@^1.1.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@probot/get-private-key/-/get-private-key-1.1.1.tgz#12bf61d00a15760d9b0bd713a794f9c4ba4ad5d3" - integrity sha512-hOmBNSAhSZc6PaNkTvj6CO9R5J67ODJ+w5XQlDW9w/6mtcpHWK4L+PZcW0YwVM7PpetLZjN6rsKQIR9yqIaWlA== - dependencies: - "@types/is-base64" "^1.1.0" - is-base64 "^1.1.0" - -"@probot/octokit-plugin-config@^1.0.0": - version "1.1.6" - resolved "https://registry.yarnpkg.com/@probot/octokit-plugin-config/-/octokit-plugin-config-1.1.6.tgz#c450a746f082c8ec9b6d1a481a71778f7720fa9b" - integrity sha512-L29wmnFvilzSfWn9tUgItxdLv0LJh2ICjma3FmLr80Spu3wZ9nHyRrKMo9R5/K2m7VuWmgoKnkgRt2zPzAQBEQ== - dependencies: - "@types/js-yaml" "^4.0.5" - js-yaml "^4.1.0" - -"@probot/pino@^2.2.0": - version "2.3.5" - resolved "https://registry.yarnpkg.com/@probot/pino/-/pino-2.3.5.tgz#f1d051edfc080c9183592e90ac8ae03c14e3951a" - integrity sha512-IiyiNZonMw1dHC4EAdD55y5owV733d9Gll/IKsrLikB7EJ54+eMCOtL/qo+OmgWN9XV3NTDfziEQF2og/OBKog== - dependencies: - "@sentry/node" "^6.0.0" - pino-pretty "^6.0.0" - pump "^3.0.0" - readable-stream "^3.6.0" - split2 "^4.0.0" - -"@sentry/core@6.19.7": - version "6.19.7" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.19.7.tgz#156aaa56dd7fad8c89c145be6ad7a4f7209f9785" - integrity sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw== - dependencies: - "@sentry/hub" "6.19.7" - "@sentry/minimal" "6.19.7" - "@sentry/types" "6.19.7" - "@sentry/utils" "6.19.7" - tslib "^1.9.3" - -"@sentry/hub@6.19.7": - version "6.19.7" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.19.7.tgz#58ad7776bbd31e9596a8ec46365b45cd8b9cfd11" - integrity sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA== - dependencies: - "@sentry/types" "6.19.7" - "@sentry/utils" "6.19.7" - tslib "^1.9.3" - -"@sentry/minimal@6.19.7": - version "6.19.7" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.19.7.tgz#b3ee46d6abef9ef3dd4837ebcb6bdfd01b9aa7b4" - integrity sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ== - dependencies: - "@sentry/hub" "6.19.7" - "@sentry/types" "6.19.7" - tslib "^1.9.3" - -"@sentry/node@^6.0.0": - version "6.19.7" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.19.7.tgz#32963b36b48daebbd559e6f13b1deb2415448592" - integrity sha512-gtmRC4dAXKODMpHXKfrkfvyBL3cI8y64vEi3fDD046uqYcrWdgoQsffuBbxMAizc6Ez1ia+f0Flue6p15Qaltg== - dependencies: - "@sentry/core" "6.19.7" - "@sentry/hub" "6.19.7" - "@sentry/types" "6.19.7" - "@sentry/utils" "6.19.7" - cookie "^0.4.1" - https-proxy-agent "^5.0.0" - lru_map "^0.3.3" - tslib "^1.9.3" - -"@sentry/types@6.19.7": - version "6.19.7" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.19.7.tgz#c6b337912e588083fc2896eb012526cf7cfec7c7" - integrity sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg== - -"@sentry/utils@6.19.7": - version "6.19.7" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.19.7.tgz#6edd739f8185fd71afe49cbe351c1bbf5e7b7c79" - integrity sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA== - dependencies: - "@sentry/types" "6.19.7" - tslib "^1.9.3" - -"@sinclair/typebox@^0.24.1": - version "0.24.51" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f" - integrity sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA== - -"@sinclair/typebox@^0.31.5": - version "0.31.5" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.31.5.tgz#10ae6c60fc523d7d695a730df1ac3dd9725ce207" - integrity sha512-4fbqH1ONle98ULTQakJFVNwGwSx+rv90HEnjZGt1GoApMKooUw1WXw3ub+Ew7rInmyDcwsjIxiHt39bkWzeCBA== - -"@sinonjs/commons@^1.7.0": - version "1.8.6" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.6.tgz#80c516a4dc264c2a69115e7578d62581ff455ed9" - integrity sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ== - dependencies: - type-detect "4.0.8" - -"@sinonjs/fake-timers@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" - integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== - dependencies: - "@sinonjs/commons" "^1.7.0" - -"@supabase/functions-js@^2.1.0": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@supabase/functions-js/-/functions-js-2.1.4.tgz#57da24829ffe8f15c002dfcc615ef4ab5735156d" - integrity sha512-5EEhei1hFCMBX4Pig4kGKjJ59DZvXwilcIBYYp4wyK/iHdAN6Vw9di9VN6/oRXRVS/6jgZd0jdmI+QgGGSxZsA== - dependencies: - cross-fetch "^3.1.5" - -"@supabase/gotrue-js@^2.46.1": - version "2.51.0" - resolved "https://registry.yarnpkg.com/@supabase/gotrue-js/-/gotrue-js-2.51.0.tgz#9e66f974c69242a01ec4c5b81088c0678dac6fd3" - integrity sha512-9bXV38OTd4tNHukwPDkfYNLyoGuzKeNPRaQ675rsv4JV7YCTliGLJiDadTCZjsMo2v1gVDDUtrJHF8kIxxPP1w== - dependencies: - "@supabase/node-fetch" "^2.6.14" - -"@supabase/node-fetch@^2.6.14": - version "2.6.14" - resolved "https://registry.yarnpkg.com/@supabase/node-fetch/-/node-fetch-2.6.14.tgz#6a3e2924e3de8aeeb82c193c786ffb25da9af23f" - integrity sha512-w/Tsd22e/5fAeoxqQ4P2MX6EyF+iM6rc9kmlMVFkHuG0rAltt2TLhFbDJfemnHbtvnazWaRfy5KnFU/SYT37dQ== - dependencies: - whatwg-url "^5.0.0" - -"@supabase/postgrest-js@^1.8.0": - version "1.8.4" - resolved "https://registry.yarnpkg.com/@supabase/postgrest-js/-/postgrest-js-1.8.4.tgz#89e8355503979ad25e7340b910d17704507ab325" - integrity sha512-ELjpvhb04wILUiJz9zIsTSwaz9LQNlX+Ig5/LgXQ7k68qQI6NqHVn+ISRNt53DngUIyOnLHjeqqIRHBZ7zpgGA== - dependencies: - "@supabase/node-fetch" "^2.6.14" - -"@supabase/realtime-js@^2.7.4": - version "2.7.4" - resolved "https://registry.yarnpkg.com/@supabase/realtime-js/-/realtime-js-2.7.4.tgz#de41195bd3f2cdd6db82d9f93c4c5b8fae9f809b" - integrity sha512-FzSzs1k9ruh/uds5AJ95Nc3beiMCCIhougExJ3O98CX1LMLAKUKFy5FivKLvcNhXnNfUEL0XUfGMb4UH2J7alg== - dependencies: - "@types/phoenix" "^1.5.4" - "@types/websocket" "^1.0.3" - websocket "^1.0.34" - -"@supabase/storage-js@^2.5.1": - version "2.5.3" - resolved "https://registry.yarnpkg.com/@supabase/storage-js/-/storage-js-2.5.3.tgz#6d6023d0420151a4c65339e762eca7838fd0f97c" - integrity sha512-wyCkBFMTiehvyLUvvvSszvhPkhaHKHcPx//fYN8NoKEa1TQwC2HuO5EIaJ5EagtAVmI1N3EFQ+M4RER6mnTaNg== - dependencies: - cross-fetch "^3.1.5" - -"@supabase/supabase-js@^2.4.0": - version "2.33.1" - resolved "https://registry.yarnpkg.com/@supabase/supabase-js/-/supabase-js-2.33.1.tgz#2407861afe63c2817d030514c87a745f78dfe68a" - integrity sha512-jA00rquPTppPOHpBB6KABW98lfg0gYXcuGqP3TB1iiduznRVsi3GGk2qBKXPDLMYSe0kRlQp5xCwWWthaJr8eA== - dependencies: - "@supabase/functions-js" "^2.1.0" - "@supabase/gotrue-js" "^2.46.1" - "@supabase/postgrest-js" "^1.8.0" - "@supabase/realtime-js" "^2.7.4" - "@supabase/storage-js" "^2.5.1" - cross-fetch "^3.1.5" - -"@telegraf/types@^6.8.1": - version "6.8.1" - resolved "https://registry.yarnpkg.com/@telegraf/types/-/types-6.8.1.tgz#c9c567e8ba4fb3c656494f3901a7dfb22cb7d676" - integrity sha512-JCRQuPPDCreYQaAeOwnqIlWrs8pJVvaNEUWBVNvdK3oJoTUKyBV+3TsPrIcnGqLeapptznuTk5s4udTlZPvGTA== - -"@tokenizer/token@^0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.3.0.tgz#fe98a93fe789247e998c75e74e9c7c63217aa276" - integrity sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A== - -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - -"@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== - -"@tsconfig/node12@^1.0.7": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" - integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== - -"@tsconfig/node14@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" - integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== - -"@tsconfig/node16@^1.0.2": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" - integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== - -"@types/aws-lambda@^8.10.85": - version "8.10.119" - resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.119.tgz#aaf010a9c892b3e29a290e5c49bfe8bcec82c455" - integrity sha512-Vqm22aZrCvCd6I5g1SvpW151jfqwTzEZ7XJ3yZ6xaZG31nUEOEyzzVImjRcsN8Wi/QyPxId/x8GTtgIbsy8kEw== - -"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": - version "7.20.1" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.1.tgz#916ecea274b0c776fec721e333e55762d3a9614b" - integrity sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw== - dependencies: - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.4" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" - integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.4.1" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" - integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": - version "7.20.1" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.1.tgz#dd6f1d2411ae677dcb2db008c962598be31d6acf" - integrity sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg== - dependencies: - "@babel/types" "^7.20.7" - -"@types/body-parser@*": - version "1.19.2" - resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" - integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== - dependencies: - "@types/connect" "*" - "@types/node" "*" - -"@types/btoa-lite@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/btoa-lite/-/btoa-lite-1.0.0.tgz#e190a5a548e0b348adb0df9ac7fa5f1151c7cca4" - integrity sha512-wJsiX1tosQ+J5+bY5LrSahHxr2wT+uME5UDwdN1kg4frt40euqA+wzECkmq4t5QbveHiJepfdThgQrPw6KiSlg== - -"@types/connect@*": - version "3.4.36" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.36.tgz#e511558c15a39cb29bd5357eebb57bd1459cd1ab" - integrity sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w== - dependencies: - "@types/node" "*" - -"@types/eslint@^8.40.2": - version "8.44.2" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.2.tgz#0d21c505f98a89b8dd4d37fa162b09da6089199a" - integrity sha512-sdPRb9K6iL5XZOmBubg8yiFp5yS/JdUDQsq5e6h95km91MCYMuvp7mh1fjPEYUhvHepKpZOjnEaMBR4PxjWDzg== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/estree@*": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" - integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== - -"@types/express-serve-static-core@^4.17.33": - version "4.17.36" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.36.tgz#baa9022119bdc05a4adfe740ffc97b5f9360e545" - integrity sha512-zbivROJ0ZqLAtMzgzIUC4oNqDG9iF0lSsAqpOD9kbs5xcIM3dTiyuHvBc7R8MtWBp3AAWGaovJa+wzWPjLYW7Q== - dependencies: - "@types/node" "*" - "@types/qs" "*" - "@types/range-parser" "*" - "@types/send" "*" - -"@types/express@^4.17.9": - version "4.17.17" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4" - integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q== - dependencies: - "@types/body-parser" "*" - "@types/express-serve-static-core" "^4.17.33" - "@types/qs" "*" - "@types/serve-static" "*" - -"@types/graceful-fs@^4.1.2": - version "4.1.6" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" - integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== - dependencies: - "@types/node" "*" - -"@types/http-errors@*": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65" - integrity sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ== - -"@types/ioredis@^4.27.1": - version "4.28.10" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.10.tgz#40ceb157a4141088d1394bb87c98ed09a75a06ff" - integrity sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ== - dependencies: - "@types/node" "*" - -"@types/is-base64@^1.1.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/is-base64/-/is-base64-1.1.1.tgz#a17d2b0075f637f80f9ab5f76f0071a65f6965d4" - integrity sha512-JgnGhP+MeSHEQmvxcobcwPEP4Ew56voiq9/0hmP/41lyQ/3gBw/ZCIRy2v+QkEOdeCl58lRcrf6+Y6WMlJGETA== - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" - integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== - -"@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" - integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== - dependencies: - "@types/istanbul-lib-report" "*" - -"@types/jest@^28.1.0": - version "28.1.8" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-28.1.8.tgz#6936409f3c9724ea431efd412ea0238a0f03b09b" - integrity sha512-8TJkV++s7B6XqnDrzR1m/TT0A0h948Pnl/097veySPN67VRAgQ4gZ7n2KfJo2rVq6njQjdxU3GCCyDvAeuHoiw== - dependencies: - expect "^28.0.0" - pretty-format "^28.0.0" - -"@types/js-yaml@^4.0.5": - version "4.0.5" - resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.5.tgz#738dd390a6ecc5442f35e7f03fa1431353f7e138" - integrity sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA== - -"@types/json-schema@*", "@types/json-schema@^7.0.9": - version "7.0.12" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" - integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== - -"@types/jsonwebtoken@^9.0.0": - version "9.0.2" - resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#9eeb56c76dd555039be2a3972218de5bd3b8d83e" - integrity sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q== - dependencies: - "@types/node" "*" - -"@types/libsodium-wrappers@^0.7.10": - version "0.7.11" - resolved "https://registry.yarnpkg.com/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.11.tgz#4ac53b8a16a4c80d062e32b3849e9d5b8c2f92ed" - integrity sha512-8avZYJny690B6lFZQEDz4PEdCgC8D8qmGE/mhJBzCwzZvsqne61tCRbtJOhxsjYMItEZd3k4SoR4xKKLnI9Ztg== - -"@types/lodash@^4.14.197": - version "4.14.198" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.198.tgz#4d27465257011aedc741a809f1269941fa2c5d4c" - integrity sha512-trNJ/vtMZYMLhfN45uLq4ShQSw0/S7xCTLLVM+WM1rmFpba/VS42jVUgaO3w/NOLiWR/09lnYk0yMaA/atdIsg== - -"@types/mime@*": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" - integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== - -"@types/mime@^1": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" - integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== - -"@types/minimist@^1.2.0": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" - integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== - -"@types/ms@^0.7.31": - version "0.7.31" - resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" - integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== - -"@types/node-fetch@^2.6.4": - version "2.6.4" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.4.tgz#1bc3a26de814f6bf466b25aeb1473fa1afe6a660" - integrity sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg== - dependencies: - "@types/node" "*" - form-data "^3.0.0" - -"@types/node@*": - version "20.6.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.0.tgz#9d7daa855d33d4efec8aea88cd66db1c2f0ebe16" - integrity sha512-najjVq5KN2vsH2U/xyh2opaSEz6cZMR2SetLIlxlj08nOcmPOemJmUK2o4kUzfLqfrWE0PIrNeE16XhYDd3nqg== - -"@types/node@16.9.1": - version "16.9.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.1.tgz#0611b37db4246c937feef529ddcc018cf8e35708" - integrity sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g== - -"@types/node@20.4.7": - version "20.4.7" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.7.tgz#74d323a93f1391a63477b27b9aec56669c98b2ab" - integrity sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g== - -"@types/node@^14.18.37": - version "14.18.59" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.59.tgz#2b61a51d875e2a4deb0c6b498ff21a78e691edc6" - integrity sha512-NWJMpBL2Xs3MY93yrD6YrrTKep8eIA6iMnfG4oIc6LrTRlBZgiSCGiY3V/Owlp6umIBLyKb4F8Q7hxWatjYH5A== - -"@types/node@^18.11.18": - version "18.17.15" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.17.15.tgz#31301a273b9ca7d568fe6d1c35ae52e0fb3f8d6a" - integrity sha512-2yrWpBk32tvV/JAd3HNHWuZn/VDN1P+72hWirHnvsvTGSqbANi+kSeuQR9yAHnbvaBvHDsoTdXV0Fe+iRtHLKA== - -"@types/normalize-package-data@^2.4.0": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" - integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== - -"@types/parse5@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-7.0.0.tgz#8b412a0a4461c84d6280a372bfa8c57a418a06bd" - integrity sha512-f2SeAxumolBmhuR62vNGTsSAvdz/Oj0k682xNrcKJ4dmRnTPODB74j6CPoNPzBPTHsu7Y7W7u93Mgp8Ovo8vWw== - dependencies: - parse5 "*" - -"@types/phoenix@^1.5.4": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@types/phoenix/-/phoenix-1.6.1.tgz#9551cd77a8f4c70c5d81db899f2af762066aabde" - integrity sha512-g2/8Ogi2zfiS25jdGT5iDSo5yjruhhXaOuOJCkOxMW28w16VxFvjtAXjBNRo7WlRS4+UXAMj3mK46UwieNM/5g== - -"@types/pino-http@^5.0.6": - version "5.8.1" - resolved "https://registry.yarnpkg.com/@types/pino-http/-/pino-http-5.8.1.tgz#ebb194750ad2f9245c3028b5d2c4e6d64f685ba9" - integrity sha512-A9MW6VCnx5ii7s+Fs5aFIw+aSZcBCpsZ/atpxamu8tTsvWFacxSf2Hrn1Ohn1jkVRB/LiPGOapRXcFawDBnDnA== - dependencies: - "@types/pino" "6.3" - -"@types/pino-pretty@*": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@types/pino-pretty/-/pino-pretty-5.0.0.tgz#aa7a61cfd553b051764acfa0a49872f7a09a1722" - integrity sha512-N1uzqSzioqz8R3AkDbSJwcfDWeI3YMPNapSQQhnB2ISU4NYgUIcAh+hYT5ygqBM+klX4htpEhXMmoJv3J7GrdA== - dependencies: - pino-pretty "*" - -"@types/pino-std-serializers@*": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz#1e28b80b554c8222858e99a4e0fc77fd070e10e8" - integrity sha512-gXfUZx2xIBbFYozGms53fT0nvkacx/+62c8iTxrEqH5PkIGAQvDbXg2774VWOycMPbqn5YJBQ3BMsg4Li3dWbg== - dependencies: - pino-std-serializers "*" - -"@types/pino@6.3", "@types/pino@^6.3.4": - version "6.3.12" - resolved "https://registry.yarnpkg.com/@types/pino/-/pino-6.3.12.tgz#4425db6ced806109c3df957100cba9dfcd73c228" - integrity sha512-dsLRTq8/4UtVSpJgl9aeqHvbh6pzdmjYD3C092SYgLD2TyoCqHpTJk6vp8DvCTGGc7iowZ2MoiYiVUUCcu7muw== - dependencies: - "@types/node" "*" - "@types/pino-pretty" "*" - "@types/pino-std-serializers" "*" - sonic-boom "^2.1.0" - -"@types/prettier@^2.0.0": - version "2.7.3" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" - integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== - -"@types/qs@*": - version "6.9.8" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.8.tgz#f2a7de3c107b89b441e071d5472e6b726b4adf45" - integrity sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg== - -"@types/range-parser@*": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" - integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== - -"@types/semver@^7.3.12": - version "7.5.1" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.1.tgz#0480eeb7221eb9bc398ad7432c9d7e14b1a5a367" - integrity sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg== - -"@types/send@*": - version "0.17.1" - resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.1.tgz#ed4932b8a2a805f1fe362a70f4e62d0ac994e301" - integrity sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q== - dependencies: - "@types/mime" "^1" - "@types/node" "*" - -"@types/serve-static@*": - version "1.15.2" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.2.tgz#3e5419ecd1e40e7405d34093f10befb43f63381a" - integrity sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw== - dependencies: - "@types/http-errors" "*" - "@types/mime" "*" - "@types/node" "*" - -"@types/source-map-support@^0.5.6": - version "0.5.7" - resolved "https://registry.yarnpkg.com/@types/source-map-support/-/source-map-support-0.5.7.tgz#68b3cc568cc4cc4d141d58edfca164c1354044b9" - integrity sha512-rJqBfLel8jPuL5MwXxMH2Cdb6D80Snu3YJxDE+VJAmtT04l7j3OA7h+FYXlYDys0WeBVH/MPbExj3B8NCaDw9g== - dependencies: - source-map "^0.6.0" - -"@types/stack-utils@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" - integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== - -"@types/websocket@^1.0.3": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.6.tgz#ec8dce5915741632ac3a4b1f951b6d4156e32d03" - integrity sha512-JXkliwz93B2cMWOI1ukElQBPN88vMg3CruvW4KVSKpflt3NyNCJImnhIuB/f97rG7kakqRJGFiwkA895Kn02Dg== - dependencies: - "@types/node" "*" - -"@types/yargs-parser@*": - version "21.0.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" - integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== - -"@types/yargs@^15.0.0": - version "15.0.15" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.15.tgz#e609a2b1ef9e05d90489c2f5f45bbfb2be092158" - integrity sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg== - dependencies: - "@types/yargs-parser" "*" - -"@types/yargs@^17.0.8": - version "17.0.24" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.24.tgz#b3ef8d50ad4aa6aecf6ddc97c580a00f5aa11902" - integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== - dependencies: - "@types/yargs-parser" "*" - -"@types/yauzl@^2.9.1": - version "2.10.0" - resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.0.tgz#b3248295276cf8c6f153ebe6a9aba0c988cb2599" - integrity sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw== - dependencies: - "@types/node" "*" - -"@typescript-eslint/eslint-plugin@^5.59.11": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db" - integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag== - dependencies: - "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.62.0" - "@typescript-eslint/type-utils" "5.62.0" - "@typescript-eslint/utils" "5.62.0" - debug "^4.3.4" - graphemer "^1.4.0" - ignore "^5.2.0" - natural-compare-lite "^1.4.0" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/parser@^5.59.11": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7" - integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA== - dependencies: - "@typescript-eslint/scope-manager" "5.62.0" - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/typescript-estree" "5.62.0" - debug "^4.3.4" - -"@typescript-eslint/scope-manager@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" - integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== - dependencies: - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/visitor-keys" "5.62.0" - -"@typescript-eslint/type-utils@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a" - integrity sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew== - dependencies: - "@typescript-eslint/typescript-estree" "5.62.0" - "@typescript-eslint/utils" "5.62.0" - debug "^4.3.4" - tsutils "^3.21.0" - -"@typescript-eslint/types@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" - integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== - -"@typescript-eslint/typescript-estree@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" - integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== - dependencies: - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/visitor-keys" "5.62.0" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/utils@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" - integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@types/json-schema" "^7.0.9" - "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.62.0" - "@typescript-eslint/types" "5.62.0" - "@typescript-eslint/typescript-estree" "5.62.0" - eslint-scope "^5.1.1" - semver "^7.3.7" - -"@typescript-eslint/visitor-keys@5.62.0": - version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" - integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== - dependencies: - "@typescript-eslint/types" "5.62.0" - eslint-visitor-keys "^3.3.0" - -"@uniswap/permit2-sdk@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@uniswap/permit2-sdk/-/permit2-sdk-1.2.0.tgz#ed86440a87a6c318169c8e6f161fc263ad040891" - integrity sha512-Ietv3FxN7+RCXcPSED/i/8b0a2GUZrMdyX05k3FsSztvYKyPFAMS/hBXojF0NZqYB1bHecqYc7Ej+7tV/rdYXg== - dependencies: - ethers "^5.3.1" - tiny-invariant "^1.3.1" - -"@vercel/ncc@^0.34.0": - version "0.34.0" - resolved "https://registry.yarnpkg.com/@vercel/ncc/-/ncc-0.34.0.tgz#d0139528320e46670d949c82967044a8f66db054" - integrity sha512-G9h5ZLBJ/V57Ou9vz5hI8pda/YQX5HQszCs3AmIus3XzsmRn/0Ptic5otD3xVST8QLKk7AMk7AqpsyQGN7MZ9A== - -JSONStream@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" - integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== - dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - -abab@^2.0.3, abab@^2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" - integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - -abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" - -accepts@~1.3.8: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - -acorn-globals@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" - integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== - dependencies: - acorn "^7.1.1" - acorn-walk "^7.1.1" - -acorn-jsx@^5.3.2: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn-walk@^7.1.1: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" - integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== - -acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - -acorn@^7.1.1: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -acorn@^8.2.4, acorn@^8.4.1, acorn@^8.9.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" - integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== - -aes-js@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" - integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== - -agent-base@6: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - -agentkeepalive@^4.2.1: - version "4.5.0" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" - integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== - dependencies: - humanize-ms "^1.2.1" - -aggregate-error@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - -ajv-formats@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" - integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== - dependencies: - ajv "^8.0.0" - -ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - 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" - -ajv@^8.0.0, ajv@^8.11.0, ajv@^8.11.2: - version "8.12.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" - integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-escapes@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-5.0.0.tgz#b6a0caf0eef0c41af190e9a749e0c00ec04bb2a6" - integrity sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA== - dependencies: - type-fest "^1.0.2" - -ansi-regex@^5.0.0, ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" - integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== - -ansi-styles@^6.0.0, ansi-styles@^6.1.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" - integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== - -any-base@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/any-base/-/any-base-1.1.0.tgz#ae101a62bc08a597b4c9ab5b7089d456630549fe" - integrity sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg== - -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - -anymatch@^3.0.3, anymatch@~3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -args@^5.0.1: - version "5.0.3" - resolved "https://registry.yarnpkg.com/args/-/args-5.0.3.tgz#943256db85021a85684be2f0882f25d796278702" - integrity sha512-h6k/zfFgusnv3i5TU08KQkVKuCPBtL/PWQbWkHUxvJrZ2nAyeaUupneemcrgn1xmqxPQsPIzwkUhOpoqPDRZuA== - dependencies: - camelcase "5.0.0" - chalk "2.4.2" - leven "2.1.0" - mri "1.1.4" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA== - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== - -array-ify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" - integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== - -array-timsort@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-timsort/-/array-timsort-1.0.3.tgz#3c9e4199e54fb2b9c3fe5976396a21614ef0d926" - integrity sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ== - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== - -arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== - -asap@^2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - -atob@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -atomic-sleep@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" - integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== - -axios@^1.3.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.0.tgz#f02e4af823e2e46a9768cfc74691fdd0517ea267" - integrity sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ== - dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - -babel-jest@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" - integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== - dependencies: - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/babel__core" "^7.1.7" - babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^26.6.2" - chalk "^4.0.0" - graceful-fs "^4.2.4" - slash "^3.0.0" - -babel-plugin-istanbul@^6.0.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" - integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@istanbuljs/load-nyc-config" "^1.0.0" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^5.0.4" - test-exclude "^6.0.0" - -babel-plugin-jest-hoist@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" - integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.0.0" - "@types/babel__traverse" "^7.0.6" - -babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== - dependencies: - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" - -babel-preset-jest@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" - integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== - dependencies: - babel-plugin-jest-hoist "^26.6.2" - babel-preset-current-node-syntax "^1.0.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base-64@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb" - integrity sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA== - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -basic-auth@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" - integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== - dependencies: - safe-buffer "5.1.2" - -bech32@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" - integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== - -before-after-hook@^2.2.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" - integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ== - -bin-links@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-4.0.2.tgz#13321472ea157e9530caded2b7281496d698665b" - integrity sha512-jxJ0PbXR8eQyPlExCvCs3JFnikvs1Yp4gUJt6nmgathdOwvur+q22KWC3h20gvWl4T/14DXKj2IlkJwwZkZPOw== - 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" - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - -bl@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" - integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - -bmp-js@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/bmp-js/-/bmp-js-0.1.0.tgz#e05a63f796a6c1ff25f4771ec7adadc148c07233" - integrity sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw== - -bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== - -body-parser@1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" - integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== - dependencies: - bytes "3.1.2" - content-type "~1.0.4" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.11.0" - raw-body "2.5.1" - type-is "~1.6.18" - unpipe "1.0.0" - -boolbase@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== - -bottleneck@^2.15.3: - version "2.19.5" - resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-2.19.5.tgz#5df0b90f59fd47656ebe63c78a98419205cadd91" - integrity sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - -braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== - -browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== - -browserslist@^4.21.9: - version "4.21.10" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" - integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== - dependencies: - caniuse-lite "^1.0.30001517" - electron-to-chromium "^1.4.477" - node-releases "^2.0.13" - update-browserslist-db "^1.0.11" - -bs-logger@0.x: - version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" - integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== - dependencies: - fast-json-stable-stringify "2.x" - -bser@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" - integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== - dependencies: - node-int64 "^0.4.0" - -btoa-lite@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" - integrity sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA== - -buffer-alloc-unsafe@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== - -buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== - dependencies: - buffer-alloc-unsafe "^1.1.0" - buffer-fill "^1.0.0" - -buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== - -buffer-equal-constant-time@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" - integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== - -buffer-equal@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" - integrity sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA== - -buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ== - -buffer-from@1.x, buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -buffer@^5.2.0, buffer@^5.2.1, buffer@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -bufferutil@^4.0.1: - version "4.0.7" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.7.tgz#60c0d19ba2c992dd8273d3f73772ffc894c153ad" - integrity sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw== - dependencies: - node-gyp-build "^4.3.0" - -bytes@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" - integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -call-bind@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -callsites@^3.0.0, callsites@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camelcase-keys@^6.2.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" - integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== - dependencies: - camelcase "^5.3.1" - map-obj "^4.0.0" - quick-lru "^4.0.1" - -camelcase@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" - integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== - -camelcase@^5.0.0, camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.0.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - -caniuse-lite@^1.0.30001517: - version "1.0.30001532" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz#c6a4d5d2da6d2b967f0ee5e12e7f680db6ad2fca" - integrity sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw== - -capture-exit@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" - integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== - dependencies: - rsvp "^4.8.4" - -chalk-template@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/chalk-template/-/chalk-template-1.1.0.tgz#ffc55db6dd745e9394b85327c8ac8466edb7a7b1" - integrity sha512-T2VJbcDuZQ0Tb2EWwSotMPJjgpy1/tGee1BTpUNsGZ/qgNjV2t7Mvu+d4600U564nbLesN1x2dPL+xii174Ekg== - dependencies: - chalk "^5.2.0" - -chalk@2.4.2, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@5.3.0, chalk@^5.2.0, chalk@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" - integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== - -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -char-regex@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" - integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== - -charenc@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" - integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== - -chokidar@^3.5.2: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -chownr@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== - -chownr@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" - integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== - -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - -ci-info@^3.2.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" - integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== - -cjs-module-lexer@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" - integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - -clear-module@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/clear-module/-/clear-module-4.1.2.tgz#5a58a5c9f8dccf363545ad7284cad3c887352a80" - integrity sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw== - dependencies: - parent-module "^2.0.0" - resolve-from "^5.0.0" - -cli-cursor@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea" - integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== - dependencies: - restore-cursor "^4.0.0" - -cli-truncate@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" - integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== - dependencies: - slice-ansi "^5.0.0" - string-width "^5.0.0" - -cliui@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" - integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^6.2.0" - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -cliui@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" - integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.1" - wrap-ansi "^7.0.0" - -cluster-key-slot@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" - integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== - -cmd-shim@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-6.0.1.tgz#a65878080548e1dca760b3aea1e21ed05194da9d" - integrity sha512-S9iI9y0nKR4hwEQsVWpyxld/6kRfGepGfzff83FcaiEBpmvlbA2nnGe7Cylgrx2f/p1P5S5wpRm9oL8z1PbS3Q== - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== - -collect-v8-coverage@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" - integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw== - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -colorette@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" - integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== - -colorette@^2.0.20, colorette@^2.0.7: - version "2.0.20" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" - integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== - -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -commander@11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67" - integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ== - -commander@^10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" - integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== - -commander@^2.19.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@^6.2.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" - integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== - -comment-json@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/comment-json/-/comment-json-4.2.3.tgz#50b487ebbf43abe44431f575ebda07d30d015365" - integrity sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw== - dependencies: - array-timsort "^1.0.3" - core-util-is "^1.0.3" - esprima "^4.0.1" - has-own-prop "^2.0.0" - repeat-string "^1.6.1" - -compare-func@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" - integrity sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA== - dependencies: - array-ify "^1.0.0" - dot-prop "^5.1.0" - -component-emitter@^1.2.1, component-emitter@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -configstore@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-6.0.0.tgz#49eca2ebc80983f77e09394a1a56e0aca8235566" - integrity sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA== - dependencies: - dot-prop "^6.0.1" - graceful-fs "^4.2.6" - unique-string "^3.0.0" - write-file-atomic "^3.0.3" - xdg-basedir "^5.0.1" - -content-disposition@0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - -content-type@~1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" - integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== - -conventional-changelog-angular@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-6.0.0.tgz#a9a9494c28b7165889144fd5b91573c4aa9ca541" - integrity sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg== - dependencies: - compare-func "^2.0.0" - -conventional-changelog-conventionalcommits@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-6.1.0.tgz#3bad05f4eea64e423d3d90fc50c17d2c8cf17652" - integrity sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw== - dependencies: - compare-func "^2.0.0" - -conventional-commits-parser@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz#02ae1178a381304839bce7cea9da5f1b549ae505" - integrity sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg== - dependencies: - JSONStream "^1.3.5" - is-text-path "^1.0.1" - meow "^8.1.2" - split2 "^3.2.2" - -convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" - integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== - -cookie@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== - -cookie@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" - integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== - -cookiejar@^2.1.3: - version "2.1.4" - resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" - integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== - -copyfiles@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5" - integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg== - dependencies: - glob "^7.0.5" - minimatch "^3.0.3" - mkdirp "^1.0.4" - noms "0.0.0" - through2 "^2.0.1" - untildify "^4.0.0" - yargs "^16.1.0" - -core-util-is@^1.0.3, core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - -cosmiconfig-typescript-loader@^4.0.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.4.0.tgz#f3feae459ea090f131df5474ce4b1222912319f9" - integrity sha512-BabizFdC3wBHhbI4kJh0VkQP9GkBfoHPydD0COMce1nJ1kJAB3F2TmJ/I7diULBKtmEWSwEbuN/KDtgnmUUVmw== - -cosmiconfig@8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.0.0.tgz#e9feae014eab580f858f8a0288f38997a7bebe97" - integrity sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ== - dependencies: - import-fresh "^3.2.1" - js-yaml "^4.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - -cosmiconfig@^8.0.0: - version "8.3.5" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.5.tgz#3b3897ddd042d022d5a207d4c8832e54f5301977" - integrity sha512-A5Xry3xfS96wy2qbiLkQLAg4JUrR2wvfybxj6yqLmrUfMAvhS3MZxIP2oQn0grgYIvJqzpeTEWu4vK0t+12NNw== - dependencies: - import-fresh "^3.3.0" - js-yaml "^4.1.0" - parse-json "^5.2.0" - path-type "^4.0.0" - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - -cross-fetch@3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" - integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== - dependencies: - node-fetch "2.6.7" - -cross-fetch@^3.1.5: - version "3.1.8" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" - integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== - dependencies: - node-fetch "^2.6.12" - -cross-spawn@^6.0.0: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -crypt@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" - integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== - -crypto-random-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-4.0.0.tgz#5a3cc53d7dd86183df5da0312816ceeeb5bb1fc2" - integrity sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA== - dependencies: - type-fest "^1.0.1" - -cspell-dictionary@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cspell-dictionary/-/cspell-dictionary-7.0.0.tgz#c6df4d8c81cd0aa0f00a6f374005bf229b9b8d6e" - integrity sha512-CYB02vB870JfCtmi4Njuzw1nCjbyRCjoqlsAQgHkhRSevRKcjFrK3+XsBhNA3Zo4ek4P35+oS/I4vMOHu6cdCg== - dependencies: - "@cspell/cspell-pipe" "7.0.0" - "@cspell/cspell-types" "7.0.0" - cspell-trie-lib "7.0.0" - fast-equals "^4.0.3" - gensequence "^5.0.2" - -cspell-gitignore@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cspell-gitignore/-/cspell-gitignore-7.0.0.tgz#8d003d562d803018624fb2816663d5dac9106877" - integrity sha512-9VVLuiVhntXO/It3K0nTDhxbPPc2nItvGLymItfUudfB0ZqgzBaomdoYZzXrcNOITjYiBXWCPuVOXLbyoL0DjQ== - dependencies: - cspell-glob "7.0.0" - find-up "^5.0.0" - -cspell-glob@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cspell-glob/-/cspell-glob-7.0.0.tgz#188d637357080598b5468a84bc432d69979fed21" - integrity sha512-Wl47kChIuSiuStofVSPdgvwi8BRD4tN03j+yhpJ1q+lWT023ctFacZy+Lc+L6nxaTUriDy5ET+UoooPMJ2PskA== - dependencies: - micromatch "^4.0.5" - -cspell-grammar@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cspell-grammar/-/cspell-grammar-7.0.0.tgz#b008feef90723538bc5ecc5af90f222f87a5faf9" - integrity sha512-0k1qVvxMNwP4WXX1zIp3Ub+RQnUzjiBtB+BO4Lprnkp6/JuRndpBRDrXBsqNZBVzZ+JjyRSU1elNSN6/nudXvQ== - dependencies: - "@cspell/cspell-pipe" "7.0.0" - "@cspell/cspell-types" "7.0.0" - -cspell-io@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cspell-io/-/cspell-io-7.0.0.tgz#ac6e96629fa7f329c71bb503dcca0e6233c57c99" - integrity sha512-pGf+XlMcOxZfO7NIwJYmje8D30OEUt2Vb7cfZ2nazdFf9/NfiZpYp3JHOT+n53DhbIXTfdmojXo5bVezPXA48g== - dependencies: - "@cspell/cspell-service-bus" "7.0.0" - node-fetch "^2.6.12" - -cspell-lib@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cspell-lib/-/cspell-lib-7.0.0.tgz#df5940bc9151f83dbd93db0b8240527618670693" - integrity sha512-CJAa7uV4hrm8OTnWdFPONSUP1Dp7J7fVhKu15aTrpNASUMAHe5YWqFqInCg+0+XhdRpGGYjQKhd+khsXL5a+bg== - dependencies: - "@cspell/cspell-bundled-dicts" "7.0.0" - "@cspell/cspell-pipe" "7.0.0" - "@cspell/cspell-types" "7.0.0" - "@cspell/strong-weak-map" "7.0.0" - clear-module "^4.1.2" - comment-json "^4.2.3" - configstore "^6.0.0" - cosmiconfig "8.0.0" - cspell-dictionary "7.0.0" - cspell-glob "7.0.0" - cspell-grammar "7.0.0" - cspell-io "7.0.0" - cspell-trie-lib "7.0.0" - fast-equals "^5.0.1" - find-up "^6.3.0" - gensequence "^5.0.2" - import-fresh "^3.3.0" - resolve-from "^5.0.0" - resolve-global "^1.0.0" - vscode-languageserver-textdocument "^1.0.8" - vscode-uri "^3.0.7" - -cspell-trie-lib@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cspell-trie-lib/-/cspell-trie-lib-7.0.0.tgz#4b13d812b531d1670f505a1ef6b4cd37cde86933" - integrity sha512-mopXyfjNRVuYbrZcbBcLwOMrWeyTezh4w8zy+RywUmsF6IW6/HM2DkfE2BmH1IyE9af29lgQqdB5eDbJLWrP5A== - dependencies: - "@cspell/cspell-pipe" "7.0.0" - "@cspell/cspell-types" "7.0.0" - gensequence "^5.0.2" - -cspell@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cspell/-/cspell-7.0.0.tgz#f77e614c60254a6dd11f7a572e91904e395f2abf" - integrity sha512-E8wQP30bTLROJsSNwYnhhRUdzVa4vQo6zILv7PqgTCSaveg8Af1HEh4ocRPRhppRgIXDpccG27+ATlpEzxiPGQ== - dependencies: - "@cspell/cspell-json-reporter" "7.0.0" - "@cspell/cspell-pipe" "7.0.0" - "@cspell/cspell-types" "7.0.0" - "@cspell/dynamic-import" "7.0.0" - chalk "^5.3.0" - chalk-template "^1.1.0" - commander "^10.0.1" - cspell-gitignore "7.0.0" - cspell-glob "7.0.0" - cspell-io "7.0.0" - cspell-lib "7.0.0" - fast-glob "^3.3.1" - fast-json-stable-stringify "^2.1.0" - file-entry-cache "^6.0.1" - get-stdin "^9.0.0" - semver "^7.5.4" - strip-ansi "^7.1.0" - vscode-uri "^3.0.7" - -css-select@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6" - integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg== - dependencies: - boolbase "^1.0.0" - css-what "^6.1.0" - domhandler "^5.0.2" - domutils "^3.0.1" - nth-check "^2.0.1" - -css-what@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" - integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== - -cssom@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" - integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== - -cssom@~0.3.6: - version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== - -cssstyle@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" - integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== - dependencies: - cssom "~0.3.6" - -d@1, d@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" - integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== - dependencies: - es5-ext "^0.10.50" - type "^1.0.1" - -dargs@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" - integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== - -data-uri-to-buffer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" - integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== - -data-urls@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" - integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== - dependencies: - abab "^2.0.3" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" - -dateformat@^4.5.1, dateformat@^4.6.3: - version "4.6.3" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" - integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== - -debug@2.6.9, debug@^2.2.0, debug@^2.3.3: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -debug@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -decamelize-keys@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.1.tgz#04a2d523b2f18d80d0158a43b895d56dff8d19d8" - integrity sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg== - dependencies: - decamelize "^1.1.0" - map-obj "^1.0.0" - -decamelize@^1.1.0, decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== - -decimal.js@^10.2.1, decimal.js@^10.4.3: - version "10.4.3" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" - integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== - -decode-uri-component@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" - integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== - -deep-is@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -deepmerge@^4.2.2: - version "4.3.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" - integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA== - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA== - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - -denque@^1.1.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" - integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== - -depd@2.0.0, depd@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -deprecation@^2.0.0, deprecation@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" - integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== - -destroy@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - -detect-newline@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" - integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== - -devtools-protocol@0.0.1019158: - version "0.0.1019158" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1019158.tgz#4b08d06108a784a2134313149626ba55f030a86f" - integrity sha512-wvq+KscQ7/6spEV7czhnZc9RM/woz1AY+/Vpd8/h2HFMwJSdTliu7f/yr1A6vDdJfKICZsShqsYpEQbdhg8AFQ== - -dezalgo@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81" - integrity sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig== - dependencies: - asap "^2.0.0" - wrappy "1" - -diff-sequences@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" - integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== - -diff-sequences@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.1.1.tgz#9989dc731266dc2903457a70e996f3a041913ac6" - integrity sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw== - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -digest-fetch@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/digest-fetch/-/digest-fetch-1.3.0.tgz#898e69264d00012a23cf26e8a3e40320143fc661" - integrity sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA== - dependencies: - base-64 "^0.1.0" - md5 "^2.3.0" - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dom-serializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" - integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== - dependencies: - domelementtype "^2.3.0" - domhandler "^5.0.2" - entities "^4.2.0" - -dom-walk@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" - integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== - -domelementtype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" - integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== - -domexception@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" - integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== - dependencies: - webidl-conversions "^5.0.0" - -domhandler@^5.0.2, domhandler@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" - integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== - dependencies: - domelementtype "^2.3.0" - -domutils@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e" - integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA== - dependencies: - dom-serializer "^2.0.0" - domelementtype "^2.3.0" - domhandler "^5.0.3" - -dot-prop@^5.1.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" - integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== - dependencies: - is-obj "^2.0.0" - -dot-prop@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" - integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== - dependencies: - is-obj "^2.0.0" - -dotenv@^8.2.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" - integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== - -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - -ecdsa-sig-formatter@1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" - integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== - dependencies: - safe-buffer "^5.0.1" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== - -electron-to-chromium@^1.4.477: - version "1.4.513" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz#41a50bf749aa7d8058ffbf7a131fc3327a7b1675" - integrity sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw== - -elliptic@6.5.4: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -emittery@^0.7.1: - version "0.7.2" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" - integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== - -end-of-stream@^1.1.0, end-of-stream@^1.4.1: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -entities@^4.2.0, entities@^4.4.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" - integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es5-ext@^0.10.35, es5-ext@^0.10.50: - version "0.10.62" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5" - integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== - dependencies: - es6-iterator "^2.0.3" - es6-symbol "^3.1.3" - next-tick "^1.1.0" - -es6-iterator@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-symbol@^3.1.1, es6-symbol@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" - integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== - dependencies: - d "^1.0.1" - ext "^1.1.2" - -esbuild@~0.18.20: - version "0.18.20" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" - integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== - 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" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -escodegen@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17" - integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== - dependencies: - esprima "^4.0.1" - estraverse "^5.2.0" - esutils "^2.0.2" - optionalDependencies: - source-map "~0.6.1" - -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" - integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== - -eslint@^8.43.0: - version "8.49.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.49.0.tgz#09d80a89bdb4edee2efcf6964623af1054bf6d42" - integrity sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.49.0" - "@humanwhocodes/config-array" "^0.11.11" - "@humanwhocodes/module-importer" "^1.0.1" - "@nodelib/fs.walk" "^1.2.8" - ajv "^6.12.4" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - doctrine "^3.0.0" - escape-string-regexp "^4.0.0" - eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" - esquery "^1.4.2" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - find-up "^5.0.0" - glob-parent "^6.0.2" - globals "^13.19.0" - graphemer "^1.4.0" - ignore "^5.2.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - is-path-inside "^3.0.3" - js-yaml "^4.1.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.1.2" - natural-compare "^1.4.0" - optionator "^0.9.3" - strip-ansi "^6.0.1" - text-table "^0.2.0" - -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== - dependencies: - acorn "^8.9.0" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" - -esprima@^4.0.0, esprima@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.4.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== - -ethers@^5.3.1, ethers@^5.7.2: - version "5.7.2" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" - integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== - dependencies: - "@ethersproject/abi" "5.7.0" - "@ethersproject/abstract-provider" "5.7.0" - "@ethersproject/abstract-signer" "5.7.0" - "@ethersproject/address" "5.7.0" - "@ethersproject/base64" "5.7.0" - "@ethersproject/basex" "5.7.0" - "@ethersproject/bignumber" "5.7.0" - "@ethersproject/bytes" "5.7.0" - "@ethersproject/constants" "5.7.0" - "@ethersproject/contracts" "5.7.0" - "@ethersproject/hash" "5.7.0" - "@ethersproject/hdnode" "5.7.0" - "@ethersproject/json-wallets" "5.7.0" - "@ethersproject/keccak256" "5.7.0" - "@ethersproject/logger" "5.7.0" - "@ethersproject/networks" "5.7.1" - "@ethersproject/pbkdf2" "5.7.0" - "@ethersproject/properties" "5.7.0" - "@ethersproject/providers" "5.7.2" - "@ethersproject/random" "5.7.0" - "@ethersproject/rlp" "5.7.0" - "@ethersproject/sha2" "5.7.0" - "@ethersproject/signing-key" "5.7.0" - "@ethersproject/solidity" "5.7.0" - "@ethersproject/strings" "5.7.0" - "@ethersproject/transactions" "5.7.0" - "@ethersproject/units" "5.7.0" - "@ethersproject/wallet" "5.7.0" - "@ethersproject/web" "5.7.1" - "@ethersproject/wordlists" "5.7.0" - -event-target-shim@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - -eventemitter3@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" - integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== - -events@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -eventsource@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.2.tgz#bc75ae1c60209e7cb1541231980460343eaea7c2" - integrity sha512-xAH3zWhgO2/3KIniEKYPr8plNSzlGINOUqYj0m0u7AB81iRw8b/3E73W6AuU+6klLbaSFmZnaETQ2lXPfAydrA== - -eventsource@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-2.0.2.tgz#76dfcc02930fb2ff339520b6d290da573a9e8508" - integrity sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA== - -exec-sh@^0.3.2: - version "0.3.6" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" - integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== - -execa@7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9" - integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.1" - human-signals "^4.3.0" - is-stream "^3.0.0" - merge-stream "^2.0.0" - npm-run-path "^5.1.0" - onetime "^6.0.0" - signal-exit "^3.0.7" - strip-final-newline "^3.0.0" - -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -execa@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" - integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== - 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" - -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - 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" - -exif-parser@^0.1.12: - version "0.1.12" - resolved "https://registry.yarnpkg.com/exif-parser/-/exif-parser-0.1.12.tgz#58a9d2d72c02c1f6f02a0ef4a9166272b7760922" - integrity sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw== - -exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA== - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -expect@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" - integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== - dependencies: - "@jest/types" "^26.6.2" - ansi-styles "^4.0.0" - jest-get-type "^26.3.0" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-regex-util "^26.0.0" - -expect@^28.0.0: - version "28.1.3" - resolved "https://registry.yarnpkg.com/expect/-/expect-28.1.3.tgz#90a7c1a124f1824133dd4533cce2d2bdcb6603ec" - integrity sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g== - dependencies: - "@jest/expect-utils" "^28.1.3" - jest-get-type "^28.0.2" - jest-matcher-utils "^28.1.3" - jest-message-util "^28.1.3" - jest-util "^28.1.3" - -exponential-backoff@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" - integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== - -express-handlebars@^6.0.3: - version "6.0.7" - resolved "https://registry.yarnpkg.com/express-handlebars/-/express-handlebars-6.0.7.tgz#f779254664eff0e250362ef1c2b30587059c212a" - integrity sha512-iYeMFpc/hMD+E6FNAZA5fgWeXnXr4rslOSPkeEV6TwdmpJ5lEXuWX0u9vFYs31P2MURctQq2batR09oeNj0LIg== - dependencies: - glob "^8.1.0" - graceful-fs "^4.2.10" - handlebars "^4.7.7" - -express@^4.17.1: - version "4.18.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" - integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.20.1" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.5.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "2.0.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.2.0" - fresh "0.5.2" - http-errors "2.0.0" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "2.4.1" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.7" - qs "6.11.0" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" - setprototypeof "1.2.0" - statuses "2.0.1" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -ext@^1.1.2: - version "1.7.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" - integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== - dependencies: - type "^2.7.2" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extract-zip@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" - integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== - dependencies: - debug "^4.1.1" - get-stream "^5.1.0" - yauzl "^2.10.0" - optionalDependencies: - "@types/yauzl" "^2.9.1" - -fast-copy@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/fast-copy/-/fast-copy-3.0.1.tgz#9e89ef498b8c04c1cd76b33b8e14271658a732aa" - integrity sha512-Knr7NOtK3HWRYGtHoJrjkaWepqT8thIVGAwt0p0aUs1zqkAzXZV4vo9fFNwyb5fcqK1GKYFYxldQdIDVKhUAfA== - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-equals@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-4.0.3.tgz#72884cc805ec3c6679b99875f6b7654f39f0e8c7" - integrity sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg== - -fast-equals@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-5.0.1.tgz#a4eefe3c5d1c0d021aeed0bc10ba5e0c12ee405d" - integrity sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ== - -fast-glob@^3.2.9, fast-glob@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" - integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== - 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" - -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== - -fast-redact@^3.0.0, fast-redact@^3.1.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.3.0.tgz#7c83ce3a7be4898241a46560d51de10f653f7634" - integrity sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ== - -fast-safe-stringify@^2.0.7, fast-safe-stringify@^2.0.8, fast-safe-stringify@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" - integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== - -fast-url-parser@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" - integrity sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ== - dependencies: - punycode "^1.3.2" - -fastq@^1.6.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" - integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== - dependencies: - reusify "^1.0.4" - -fb-watchman@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" - integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== - dependencies: - bser "2.1.1" - -fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g== - dependencies: - pend "~1.2.0" - -fetch-blob@^3.1.2, fetch-blob@^3.1.4: - version "3.2.0" - resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" - integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== - dependencies: - node-domexception "^1.0.0" - web-streams-polyfill "^3.0.3" - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - -file-type@^16.5.4: - version "16.5.4" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-16.5.4.tgz#474fb4f704bee427681f98dd390058a172a6c2fd" - integrity sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw== - dependencies: - readable-web-to-node-stream "^3.0.0" - strtok3 "^6.2.4" - token-types "^4.1.1" - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ== - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "2.4.1" - parseurl "~1.3.3" - statuses "2.0.1" - unpipe "~1.0.0" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -find-up@^4.0.0, find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -find-up@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-6.3.0.tgz#2abab3d3280b2dc7ac10199ef324c4e002c8c790" - integrity sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw== - dependencies: - locate-path "^7.1.0" - path-exists "^5.0.0" - -flat-cache@^3.0.4: - version "3.1.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.0.tgz#0e54ab4a1a60fe87e2946b6b00657f1c99e1af3f" - integrity sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew== - dependencies: - flatted "^3.2.7" - keyv "^4.5.3" - rimraf "^3.0.2" - -flatstr@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/flatstr/-/flatstr-1.0.12.tgz#c2ba6a08173edbb6c9640e3055b95e287ceb5931" - integrity sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw== - -flatted@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" - integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== - -follow-redirects@^1.15.0: - version "1.15.2" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" - integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== - -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== - -form-data-encoder@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040" - integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A== - -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -formdata-node@^4.3.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2" - integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ== - dependencies: - node-domexception "1.0.0" - web-streams-polyfill "4.0.0-beta.3" - -formdata-polyfill@^4.0.10: - version "4.0.10" - resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" - integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== - dependencies: - fetch-blob "^3.1.2" - -formidable@^2.0.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.1.2.tgz#fa973a2bec150e4ce7cac15589d7a25fc30ebd89" - integrity sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g== - dependencies: - dezalgo "^1.0.4" - hexoid "^1.0.0" - once "^1.4.0" - qs "^6.11.0" - -forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA== - dependencies: - map-cache "^0.2.2" - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== - -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== - -fs-extra@^11.0.0: - version "11.1.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d" - integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-minipass@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" - integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== - dependencies: - minipass "^3.0.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -fsevents@^2.1.2, fsevents@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -gensequence@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/gensequence/-/gensequence-5.0.2.tgz#f065be2f9a5b2967b9cad7f33b2d79ce1f22dc82" - integrity sha512-JlKEZnFc6neaeSVlkzBGGgkIoIaSxMgvdamRoPN8r3ozm2r9dusqxeKqYQ7lhzmj2UhFQP8nkyfCaiLQxiLrDA== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-caller-file@^2.0.1, get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-intrinsic@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" - 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" - -get-package-type@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" - integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== - -get-stdin@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575" - integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA== - -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - -get-stream@^5.0.0, get-stream@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== - dependencies: - pump "^3.0.0" - -get-stream@^6.0.0, get-stream@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -get-tsconfig@^4.4.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.0.tgz#06ce112a1463e93196aa90320c35df5039147e34" - integrity sha512-pmjiZ7xtB8URYm74PlGJozDNyhvsVLUcpBa8DZBG3bWHwaHa9bPiRpiSfovw+fjhwONSCWKRyk+JQHEGZmMrzw== - dependencies: - resolve-pkg-maps "^1.0.0" - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== - -gifwrap@^0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/gifwrap/-/gifwrap-0.10.1.tgz#9ed46a5d51913b482d4221ce9c727080260b681e" - integrity sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw== - dependencies: - image-q "^4.0.0" - omggif "^1.0.10" - -git-raw-commits@^2.0.11: - version "2.0.11" - resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.11.tgz#bc3576638071d18655e1cc60d7f524920008d723" - integrity sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A== - dependencies: - dargs "^7.0.0" - lodash "^4.17.15" - meow "^8.0.0" - split2 "^3.0.0" - through2 "^4.0.0" - -glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-parent@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - -glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - 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" - -glob@^8.0.0, glob@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" - integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^5.0.1" - once "^1.3.0" - -global-dirs@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" - integrity sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg== - dependencies: - ini "^1.3.4" - -global@~4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" - integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== - dependencies: - min-document "^2.19.0" - process "^0.11.10" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^13.19.0: - version "13.21.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.21.0.tgz#163aae12f34ef502f5153cfbdd3600f36c63c571" - integrity sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg== - dependencies: - type-fest "^0.20.2" - -globby@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - -graceful-fs@^4.1.15, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.10, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: - version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - -graphemer@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" - integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== - -growly@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - integrity sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw== - -handlebars@^4.5.3, handlebars@^4.7.7: - version "4.7.8" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" - integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== - 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" - -hard-rejection@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" - integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-own-prop@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-own-prop/-/has-own-prop-2.0.0.tgz#f0f95d58f65804f5d218db32563bb85b8e0417af" - integrity sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ== - -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== - -has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q== - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw== - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ== - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ== - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -he@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -help-me@^4.0.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/help-me/-/help-me-4.2.0.tgz#50712bfd799ff1854ae1d312c36eafcea85b0563" - integrity sha512-TAOnTB8Tz5Dw8penUuzHVrKNKlCIbwwbHnXraNJxPwf8LRtE2HlM84RYuezMFcwOJmoYOCWVDyJ8TQGxn9PgxA== - dependencies: - glob "^8.0.0" - readable-stream "^3.6.0" - -hexoid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18" - integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g== - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -hosted-git-info@^2.1.4: - version "2.8.9" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" - integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== - -hosted-git-info@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" - integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== - dependencies: - lru-cache "^6.0.0" - -html-encoding-sniffer@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" - integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== - dependencies: - whatwg-encoding "^1.0.5" - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -http-errors@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - -https-proxy-agent@5.0.1, https-proxy-agent@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" - integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== - dependencies: - agent-base "6" - debug "4" - -human-signals@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" - integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -human-signals@^4.3.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" - integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== - -humanize-ms@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" - integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== - dependencies: - ms "^2.0.0" - -husky@^8.0.2: - version "8.0.3" - resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" - integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== - -iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -ieee754@^1.1.13, ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -ignore-by-default@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" - integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA== - -ignore@^5.2.0: - version "5.2.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" - integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== - -image-q@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/image-q/-/image-q-4.0.0.tgz#31e075be7bae3c1f42a85c469b4732c358981776" - integrity sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw== - dependencies: - "@types/node" "16.9.1" - -import-fresh@^3.0.0, import-fresh@^3.2.1, import-fresh@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-local@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" - integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== - dependencies: - pkg-dir "^4.2.0" - resolve-cwd "^3.0.0" - -import-meta-resolve@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-3.0.0.tgz#94a6aabc623874fbc2f3525ec1300db71c6cbc11" - integrity sha512-4IwhLhNNA8yy445rPjD/lWh++7hMDOml2eHtd58eG7h+qK3EryMuuRbsHGPikCoAgIkkDnckKfWSk2iDla/ejg== - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -ini@^1.3.4: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - -ioredis@^4.27.8: - version "4.28.5" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.5.tgz#5c149e6a8d76a7f8fa8a504ffc85b7d5b6797f9f" - integrity sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A== - dependencies: - cluster-key-slot "^1.1.0" - debug "^4.3.1" - denque "^1.1.0" - lodash.defaults "^4.2.0" - lodash.flatten "^4.4.0" - lodash.isarguments "^3.1.0" - p-map "^2.1.0" - redis-commands "1.7.0" - redis-errors "^1.2.0" - redis-parser "^3.0.0" - standard-as-callback "^2.1.0" - -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A== - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== - -is-base64@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-base64/-/is-base64-1.1.0.tgz#8ce1d719895030a457c59a7dcaf39b66d99d56b4" - integrity sha512-Nlhg7Z2dVC4/PTvIFkgVVNvPHSO2eR/Yd0XzhGiXCXEvWnptXlXa/clQ8aePPiMuxEGcWfzWbGw2Fe3d+Y3v1g== - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-buffer@^1.1.5, is-buffer@~1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - -is-core-module@^2.13.0, is-core-module@^2.5.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" - integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== - dependencies: - has "^1.0.3" - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg== - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-docker@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-fullwidth-code-point@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" - integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== - -is-function@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" - integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== - -is-generator-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" - integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== - dependencies: - kind-of "^3.0.2" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - -is-path-inside@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - -is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== - -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-plain-object@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" - integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== - -is-potential-custom-element-name@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" - integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== - -is-promise@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3" - integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ== - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" - integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== - -is-text-path@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" - integrity sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w== - dependencies: - text-extensions "^1.0.0" - -is-typedarray@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== - -isarray@1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA== - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== - -isomorphic-fetch@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz#0267b005049046d2421207215d45d6a262b8b8b4" - integrity sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA== - dependencies: - node-fetch "^2.6.1" - whatwg-fetch "^3.4.1" - -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== - -istanbul-lib-instrument@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" - integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== - dependencies: - "@babel/core" "^7.7.5" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" - semver "^6.3.0" - -istanbul-lib-instrument@^5.0.4: - version "5.2.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" - integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^6.3.0" - -istanbul-lib-report@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" - integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^4.0.0" - supports-color "^7.1.0" - -istanbul-lib-source-maps@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" - integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - -istanbul-reports@^3.0.2: - version "3.1.6" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" - integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -jest-changed-files@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" - integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== - dependencies: - "@jest/types" "^26.6.2" - execa "^4.0.0" - throat "^5.0.0" - -jest-cli@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" - integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== - dependencies: - "@jest/core" "^26.6.3" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.4" - import-local "^3.0.2" - is-ci "^2.0.0" - jest-config "^26.6.3" - jest-util "^26.6.2" - jest-validate "^26.6.2" - prompts "^2.0.1" - yargs "^15.4.1" - -jest-config@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" - integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== - dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^26.6.3" - "@jest/types" "^26.6.2" - babel-jest "^26.6.3" - chalk "^4.0.0" - deepmerge "^4.2.2" - glob "^7.1.1" - graceful-fs "^4.2.4" - jest-environment-jsdom "^26.6.2" - jest-environment-node "^26.6.2" - jest-get-type "^26.3.0" - jest-jasmine2 "^26.6.3" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" - micromatch "^4.0.2" - pretty-format "^26.6.2" - -jest-diff@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" - integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== - dependencies: - chalk "^4.0.0" - diff-sequences "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - -jest-diff@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-28.1.3.tgz#948a192d86f4e7a64c5264ad4da4877133d8792f" - integrity sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw== - dependencies: - chalk "^4.0.0" - diff-sequences "^28.1.1" - jest-get-type "^28.0.2" - pretty-format "^28.1.3" - -jest-docblock@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" - integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== - dependencies: - detect-newline "^3.0.0" - -jest-each@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" - integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== - dependencies: - "@jest/types" "^26.6.2" - chalk "^4.0.0" - jest-get-type "^26.3.0" - jest-util "^26.6.2" - pretty-format "^26.6.2" - -jest-environment-jsdom@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" - integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== - dependencies: - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - jest-mock "^26.6.2" - jest-util "^26.6.2" - jsdom "^16.4.0" - -jest-environment-node@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" - integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== - dependencies: - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - jest-mock "^26.6.2" - jest-util "^26.6.2" - -jest-get-type@^26.3.0: - version "26.3.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" - integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== - -jest-get-type@^28.0.2: - version "28.0.2" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" - integrity sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA== - -jest-haste-map@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" - integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== - dependencies: - "@jest/types" "^26.6.2" - "@types/graceful-fs" "^4.1.2" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - jest-regex-util "^26.0.0" - jest-serializer "^26.6.2" - jest-util "^26.6.2" - jest-worker "^26.6.2" - micromatch "^4.0.2" - sane "^4.0.3" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.1.2" - -jest-jasmine2@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" - integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== - dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^26.6.2" - "@jest/source-map" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - expect "^26.6.2" - is-generator-fn "^2.0.0" - jest-each "^26.6.2" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-runtime "^26.6.3" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - pretty-format "^26.6.2" - throat "^5.0.0" - -jest-leak-detector@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" - integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== - dependencies: - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - -jest-matcher-utils@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" - integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== - dependencies: - chalk "^4.0.0" - jest-diff "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - -jest-matcher-utils@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz#5a77f1c129dd5ba3b4d7fc20728806c78893146e" - integrity sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw== - dependencies: - chalk "^4.0.0" - jest-diff "^28.1.3" - jest-get-type "^28.0.2" - pretty-format "^28.1.3" - -jest-message-util@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" - integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== - dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/types" "^26.6.2" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.4" - micromatch "^4.0.2" - pretty-format "^26.6.2" - slash "^3.0.0" - stack-utils "^2.0.2" - -jest-message-util@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-28.1.3.tgz#232def7f2e333f1eecc90649b5b94b0055e7c43d" - integrity sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g== - dependencies: - "@babel/code-frame" "^7.12.13" - "@jest/types" "^28.1.3" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - micromatch "^4.0.4" - pretty-format "^28.1.3" - slash "^3.0.0" - stack-utils "^2.0.3" - -jest-mock@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" - integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== - dependencies: - "@jest/types" "^26.6.2" - "@types/node" "*" - -jest-pnp-resolver@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" - integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== - -jest-regex-util@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" - integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== - -jest-resolve-dependencies@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" - integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== - dependencies: - "@jest/types" "^26.6.2" - jest-regex-util "^26.0.0" - jest-snapshot "^26.6.2" - -jest-resolve@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" - integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== - dependencies: - "@jest/types" "^26.6.2" - chalk "^4.0.0" - graceful-fs "^4.2.4" - jest-pnp-resolver "^1.2.2" - jest-util "^26.6.2" - read-pkg-up "^7.0.1" - resolve "^1.18.1" - slash "^3.0.0" - -jest-runner@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" - integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== - dependencies: - "@jest/console" "^26.6.2" - "@jest/environment" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - emittery "^0.7.1" - exit "^0.1.2" - graceful-fs "^4.2.4" - jest-config "^26.6.3" - jest-docblock "^26.0.0" - jest-haste-map "^26.6.2" - jest-leak-detector "^26.6.2" - jest-message-util "^26.6.2" - jest-resolve "^26.6.2" - jest-runtime "^26.6.3" - jest-util "^26.6.2" - jest-worker "^26.6.2" - source-map-support "^0.5.6" - throat "^5.0.0" - -jest-runtime@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" - integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== - dependencies: - "@jest/console" "^26.6.2" - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/globals" "^26.6.2" - "@jest/source-map" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - cjs-module-lexer "^0.6.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.2.4" - jest-config "^26.6.3" - jest-haste-map "^26.6.2" - jest-message-util "^26.6.2" - jest-mock "^26.6.2" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" - slash "^3.0.0" - strip-bom "^4.0.0" - yargs "^15.4.1" - -jest-serializer@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" - integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== - dependencies: - "@types/node" "*" - graceful-fs "^4.2.4" - -jest-snapshot@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" - integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== - dependencies: - "@babel/types" "^7.0.0" - "@jest/types" "^26.6.2" - "@types/babel__traverse" "^7.0.4" - "@types/prettier" "^2.0.0" - chalk "^4.0.0" - expect "^26.6.2" - graceful-fs "^4.2.4" - jest-diff "^26.6.2" - jest-get-type "^26.3.0" - jest-haste-map "^26.6.2" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-resolve "^26.6.2" - natural-compare "^1.4.0" - pretty-format "^26.6.2" - semver "^7.3.2" - -jest-util@^26.1.0, jest-util@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" - integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== - dependencies: - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - graceful-fs "^4.2.4" - is-ci "^2.0.0" - micromatch "^4.0.2" - -jest-util@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.3.tgz#f4f932aa0074f0679943220ff9cbba7e497028b0" - integrity sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ== - dependencies: - "@jest/types" "^28.1.3" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - -jest-validate@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" - integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== - dependencies: - "@jest/types" "^26.6.2" - camelcase "^6.0.0" - chalk "^4.0.0" - jest-get-type "^26.3.0" - leven "^3.1.0" - pretty-format "^26.6.2" - -jest-watcher@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" - integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== - dependencies: - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - jest-util "^26.6.2" - string-length "^4.0.1" - -jest-worker@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" - integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^7.0.0" - -jest@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" - integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== - dependencies: - "@jest/core" "^26.6.3" - import-local "^3.0.2" - jest-cli "^26.6.3" - -jimp@^0.22.4: - version "0.22.10" - resolved "https://registry.yarnpkg.com/jimp/-/jimp-0.22.10.tgz#2cc3e265a99cdbe69ec60ddd57cbcde6a6cf0519" - integrity sha512-lCaHIJAgTOsplyJzC1w/laxSxrbSsEBw4byKwXgUdMmh+ayPsnidTblenQm+IvhIs44Gcuvlb6pd2LQ0wcKaKg== - dependencies: - "@jimp/custom" "^0.22.10" - "@jimp/plugins" "^0.22.10" - "@jimp/types" "^0.22.10" - regenerator-runtime "^0.13.3" - -jmespath@^0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" - integrity sha512-+kHj8HXArPfpPEKGLZ+kB5ONRTCiGQXo8RQYL0hH8t6pWXUBBK5KkkQmTNOwKK4LEsd0yTsgtjJVm4UBSZea4w== - -joycon@^3.0.0, joycon@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" - integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== - -jpeg-js@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa" - integrity sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg== - -js-sha3@0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1, js-yaml@^3.14.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -jsdom@^16.4.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" - integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== - dependencies: - abab "^2.0.5" - acorn "^8.2.4" - acorn-globals "^6.0.0" - cssom "^0.4.4" - cssstyle "^2.3.0" - data-urls "^2.0.0" - decimal.js "^10.2.1" - domexception "^2.0.1" - escodegen "^2.0.0" - form-data "^3.0.0" - html-encoding-sniffer "^2.0.1" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-potential-custom-element-name "^1.0.1" - nwsapi "^2.2.0" - parse5 "6.0.1" - saxes "^5.0.1" - symbol-tree "^3.2.4" - tough-cookie "^4.0.0" - w3c-hr-time "^1.0.2" - w3c-xmlserializer "^2.0.0" - webidl-conversions "^6.1.0" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.5.0" - ws "^7.4.6" - xml-name-validator "^3.0.0" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== - -json-stringify-safe@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== - -json5@2.x, json5@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -jsonparse@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== - -jsonwebtoken@^9.0.0, jsonwebtoken@^9.0.2: - version "9.0.2" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" - integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== - dependencies: - jws "^3.2.2" - lodash.includes "^4.3.0" - lodash.isboolean "^3.0.3" - lodash.isinteger "^4.0.4" - lodash.isnumber "^3.0.3" - lodash.isplainobject "^4.0.6" - lodash.isstring "^4.0.1" - lodash.once "^4.0.0" - ms "^2.1.1" - semver "^7.5.4" - -jwa@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" - integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== - dependencies: - buffer-equal-constant-time "1.0.1" - ecdsa-sig-formatter "1.0.11" - safe-buffer "^5.0.1" - -jws@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" - integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== - dependencies: - jwa "^1.4.1" - safe-buffer "^5.0.1" - -keyv@^4.5.3: - version "4.5.3" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.3.tgz#00873d2b046df737963157bd04f294ca818c9c25" - integrity sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug== - dependencies: - json-buffer "3.0.1" - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw== - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - -leven@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" - integrity sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA== - -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -libsodium-wrappers@^0.7.11: - version "0.7.11" - resolved "https://registry.yarnpkg.com/libsodium-wrappers/-/libsodium-wrappers-0.7.11.tgz#53bd20606dffcc54ea2122133c7da38218f575f7" - integrity sha512-SrcLtXj7BM19vUKtQuyQKiQCRJPgbpauzl3s0rSwD+60wtHqSUuqcoawlMDheCJga85nKOQwxNYQxf/CKAvs6Q== - dependencies: - libsodium "^0.7.11" - -libsodium@^0.7.11: - version "0.7.11" - resolved "https://registry.yarnpkg.com/libsodium/-/libsodium-0.7.11.tgz#cd10aae7bcc34a300cc6ad0ac88fcca674cfbc2e" - integrity sha512-WPfJ7sS53I2s4iM58QxY3Inb83/6mjlYgcmZs7DJsvDlnmVUwNinBCi5vBT43P6bHRy01O4zsMU2CoVR6xJ40A== - -lilconfig@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" - integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== - -lines-and-columns@^1.1.6: - version "1.2.4" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" - integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== - -lint-staged@^13.1.0: - version "13.3.0" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.3.0.tgz#7965d72a8d6a6c932f85e9c13ccf3596782d28a5" - integrity sha512-mPRtrYnipYYv1FEE134ufbWpeggNTo+O/UPzngoaKzbzHAthvR55am+8GfHTnqNRQVRRrYQLGW9ZyUoD7DsBHQ== - dependencies: - chalk "5.3.0" - commander "11.0.0" - debug "4.3.4" - execa "7.2.0" - lilconfig "2.1.0" - listr2 "6.6.1" - micromatch "4.0.5" - pidtree "0.6.0" - string-argv "0.3.2" - yaml "2.3.1" - -listr2@6.6.1: - version "6.6.1" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-6.6.1.tgz#08b2329e7e8ba6298481464937099f4a2cd7f95d" - integrity sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg== - dependencies: - cli-truncate "^3.1.0" - colorette "^2.0.20" - eventemitter3 "^5.0.1" - log-update "^5.0.1" - rfdc "^1.3.0" - wrap-ansi "^8.1.0" - -load-bmfont@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/load-bmfont/-/load-bmfont-1.4.1.tgz#c0f5f4711a1e2ccff725a7b6078087ccfcddd3e9" - integrity sha512-8UyQoYmdRDy81Brz6aLAUhfZLwr5zV0L3taTQ4hju7m6biuwiWiJXjPhBJxbUQJA8PrkvJ/7Enqmwk2sM14soA== - dependencies: - buffer-equal "0.0.1" - mime "^1.3.4" - parse-bmfont-ascii "^1.0.3" - parse-bmfont-binary "^1.0.5" - parse-bmfont-xml "^1.1.4" - phin "^2.9.1" - xhr "^2.0.1" - xtend "^4.0.0" - -load-json-file@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-5.3.0.tgz#4d3c1e01fa1c03ea78a60ac7af932c9ce53403f3" - integrity sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw== - dependencies: - graceful-fs "^4.1.15" - parse-json "^4.0.0" - pify "^4.0.1" - strip-bom "^3.0.0" - type-fest "^0.3.0" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -locate-path@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-7.2.0.tgz#69cb1779bd90b35ab1e771e1f2f89a202c2a8a8a" - integrity sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA== - dependencies: - p-locate "^6.0.0" - -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== - -lodash.defaults@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" - integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== - -lodash.flatten@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" - integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== - -lodash.includes@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" - integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== - -lodash.isarguments@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== - -lodash.isboolean@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" - integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== - -lodash.isfunction@^3.0.9: - version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" - integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw== - -lodash.isinteger@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" - integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== - -lodash.isnumber@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" - integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== - -lodash.isplainobject@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== - -lodash.isstring@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" - integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== - -lodash.kebabcase@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" - integrity sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g== - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash.mergewith@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" - integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== - -lodash.once@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" - integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== - -lodash.snakecase@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d" - integrity sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw== - -lodash.startcase@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.startcase/-/lodash.startcase-4.4.0.tgz#9436e34ed26093ed7ffae1936144350915d9add8" - integrity sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg== - -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== - -lodash.upperfirst@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" - integrity sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg== - -lodash@4.x, lodash@^4.17.15, lodash@^4.17.21, lodash@^4.7.0: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-update@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-5.0.1.tgz#9e928bf70cb183c1f0c9e91d9e6b7115d597ce09" - integrity sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw== - dependencies: - ansi-escapes "^5.0.0" - cli-cursor "^4.0.0" - slice-ansi "^5.0.0" - strip-ansi "^7.0.1" - wrap-ansi "^8.0.1" - -lowercase-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" - integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -lru-cache@^9.0.0: - version "9.1.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-9.1.2.tgz#255fdbc14b75589d6d0e73644ca167a8db506835" - integrity sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ== - -lru_map@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" - integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== - -make-dir@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" - integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== - dependencies: - semver "^7.5.3" - -make-error@1.x, make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -makeerror@1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" - integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== - dependencies: - tmpl "1.0.5" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== - -map-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== - -map-obj@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" - integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w== - dependencies: - object-visit "^1.0.0" - -md5@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" - integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== - dependencies: - charenc "0.0.2" - crypt "0.0.2" - is-buffer "~1.1.6" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== - -meow@^8.0.0, meow@^8.1.2: - version "8.1.2" - resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" - integrity sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q== - dependencies: - "@types/minimist" "^1.2.0" - camelcase-keys "^6.2.2" - decamelize-keys "^1.1.0" - hard-rejection "^2.1.0" - minimist-options "4.1.0" - normalize-package-data "^3.0.0" - read-pkg-up "^7.0.1" - redent "^3.0.0" - trim-newlines "^3.0.0" - type-fest "^0.18.0" - yargs-parser "^20.2.3" - -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -methods@^1.1.2, methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== - -micromatch@4.0.5, micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - -micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mime@1.6.0, mime@^1.3.4: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mime@2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" - integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -mimic-fn@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" - integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== - -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - integrity sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ== - dependencies: - dom-walk "^0.1.0" - -min-indent@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" - integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== - -minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^5.0.1: - version "5.1.6" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" - integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== - dependencies: - brace-expansion "^2.0.1" - -minimist-options@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" - integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - kind-of "^6.0.3" - -minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -minipass@^3.0.0: - version "3.3.6" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" - integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== - dependencies: - yallist "^4.0.0" - -minipass@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" - integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== - -minizlib@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" - integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== - dependencies: - minipass "^3.0.0" - yallist "^4.0.0" - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp-classic@^0.5.2: - version "0.5.3" - resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" - integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== - -mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -morgan@^1.9.1: - version "1.10.0" - resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" - integrity sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ== - dependencies: - basic-auth "~2.0.1" - debug "2.6.9" - depd "~2.0.0" - on-finished "~2.3.0" - on-headers "~1.0.2" - -mri@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" - integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w== - -mri@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" - integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -natural-compare-lite@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" - integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - -neo-async@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - -next-tick@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" - integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -nock@^13.0.5: - version "13.3.3" - resolved "https://registry.yarnpkg.com/nock/-/nock-13.3.3.tgz#179759c07d3f88ad3e794ace885629c1adfd3fe7" - integrity sha512-z+KUlILy9SK/RjpeXDiDUEAq4T94ADPHE3qaRkf66mpEhzc/ytOMm3Bwdrbq6k1tMWkbdujiKim3G2tfQARuJw== - dependencies: - debug "^4.1.0" - json-stringify-safe "^5.0.1" - lodash "^4.17.21" - propagate "^2.0.0" - -node-domexception@1.0.0, node-domexception@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" - integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== - -node-fetch@2.6.7: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - -node-fetch@^2.6.1, node-fetch@^2.6.7, node-fetch@^2.6.8: - version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - -node-fetch@^2.6.12: - version "2.6.13" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.13.tgz#a20acbbec73c2e09f9007de5cda17104122e0010" - integrity sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA== - dependencies: - whatwg-url "^5.0.0" - -node-fetch@^3.2.10: - version "3.3.2" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.2.tgz#d1e889bacdf733b4ff3b2b243eb7a12866a0b78b" - integrity sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA== - dependencies: - data-uri-to-buffer "^4.0.0" - fetch-blob "^3.1.4" - formdata-polyfill "^4.0.10" - -node-gyp-build@^4.3.0: - version "4.6.1" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.1.tgz#24b6d075e5e391b8d5539d98c7fc5c210cac8a3e" - integrity sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ== - -node-html-parser@^6.1.5: - version "6.1.8" - resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-6.1.8.tgz#e4865b891d4e356c1e3171d25101cbb062b68940" - integrity sha512-bi3ChNi5Ne8XM2vDPvE2TOS6+AjgD9ASRJ81P1+45VTe9odNbsNb3SvVZzHho4qnu5gJ1yUYLGlQZ7tveSYNSg== - dependencies: - css-select "^5.1.0" - he "1.2.0" - -node-html-to-image@^3.3.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/node-html-to-image/-/node-html-to-image-3.4.0.tgz#d31174e5df71299280899b3884a619221c6f21f0" - integrity sha512-oQlQmOaiUZP2gG7rokVvynJaEEaWCaa0JxN24DQmFdkQY6QQ4tFSiFw2wcP52ddvdQ+WetFL90QdTZXS7V7uiQ== - dependencies: - handlebars "^4.5.3" - puppeteer "^15.3.0" - puppeteer-cluster "^0.23.0" - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== - -node-notifier@^8.0.0: - version "8.0.2" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5" - integrity sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg== - dependencies: - growly "^1.3.0" - is-wsl "^2.2.0" - semver "^7.3.2" - shellwords "^0.1.1" - uuid "^8.3.0" - which "^2.0.2" - -node-releases@^2.0.13: - version "2.0.13" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" - integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== - -nodemon@^2.0.19: - version "2.0.22" - resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.22.tgz#182c45c3a78da486f673d6c1702e00728daf5258" - integrity sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ== - dependencies: - chokidar "^3.5.2" - debug "^3.2.7" - ignore-by-default "^1.0.1" - minimatch "^3.1.2" - pstree.remy "^1.1.8" - semver "^5.7.1" - simple-update-notifier "^1.0.7" - supports-color "^5.5.0" - touch "^3.1.0" - undefsafe "^2.0.5" - -noms@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859" - integrity sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow== - dependencies: - inherits "^2.0.1" - readable-stream "~1.0.31" - -nopt@~1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" - integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg== - dependencies: - abbrev "1" - -normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-package-data@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" - integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== - dependencies: - hosted-git-info "^4.0.1" - is-core-module "^2.5.0" - semver "^7.3.4" - validate-npm-package-license "^3.0.1" - -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w== - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -npm-normalize-package-bin@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz#25447e32a9a7de1f51362c61a559233b89947832" - integrity sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ== - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw== - dependencies: - path-key "^2.0.0" - -npm-run-path@^4.0.0, npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -npm-run-path@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" - integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== - dependencies: - path-key "^4.0.0" - -nth-check@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" - integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== - dependencies: - boolbase "^1.0.0" - -nwsapi@^2.2.0: - version "2.2.7" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" - integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ== - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-inspect@^1.9.0: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA== - dependencies: - isobject "^3.0.0" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ== - dependencies: - isobject "^3.0.1" - -octokit-auth-probot@^1.2.2: - version "1.2.9" - resolved "https://registry.yarnpkg.com/octokit-auth-probot/-/octokit-auth-probot-1.2.9.tgz#835178f2f13209687c23e794af84b373f234b01a" - integrity sha512-mMjw6Y760EwJnW2tSVooJK8BMdsG6D40SoCclnefVf/5yWjaNVquEu8NREBVWb60OwbpnMEz4vREXHB5xdMFYQ== - dependencies: - "@octokit/auth-app" "^4.0.2" - "@octokit/auth-token" "^3.0.0" - "@octokit/auth-unauthenticated" "^3.0.0" - "@octokit/types" "^8.0.0" - -omggif@^1.0.10, omggif@^1.0.9: - version "1.0.10" - resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.10.tgz#ddaaf90d4a42f532e9e7cb3a95ecdd47f17c7b19" - integrity sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw== - -on-exit-leak-free@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz#5c703c968f7e7f851885f6459bf8a8a57edc9cc4" - integrity sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w== - -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -onetime@^5.1.0, onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -onetime@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" - integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== - dependencies: - mimic-fn "^4.0.0" - -openai@^4.2.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/openai/-/openai-4.6.0.tgz#0335111cf71c608b68dbdca19f8ccbd9cfb0cd97" - integrity sha512-LuONkTgoe4D172raQCv+eEK5OdLGnY/M4JrUz/pxRGevZwqDqy3xhBbCeWX8QLCbFcnITYsu/VBJXZJ0rDAMpA== - dependencies: - "@types/node" "^18.11.18" - "@types/node-fetch" "^2.6.4" - abort-controller "^3.0.0" - agentkeepalive "^4.2.1" - digest-fetch "^1.3.0" - form-data-encoder "1.7.2" - formdata-node "^4.3.2" - node-fetch "^2.6.7" - -optionator@^0.9.3: - version "0.9.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" - integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== - dependencies: - "@aashutoshrathi/word-wrap" "^1.2.3" - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - -p-each-series@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" - integrity sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA== - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== - -p-limit@^2.0.0, p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-limit@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644" - integrity sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ== - dependencies: - yocto-queue "^1.0.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -p-locate@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-6.0.0.tgz#3da9a49d4934b901089dca3302fa65dc5a05c04f" - integrity sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw== - dependencies: - p-limit "^4.0.0" - -p-map@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== - -p-timeout@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-4.1.0.tgz#788253c0452ab0ffecf18a62dff94ff1bd09ca0a" - integrity sha512-+/wmHtzJuWii1sXn3HCuH/FTwGhrp4tmJTxSKJbfS+vkipci6osxXM5mY0jUiRzWKMTgUT8l7HFbeSwZAynqHw== - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -pako@^1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" - integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parent-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-2.0.0.tgz#fa71f88ff1a50c27e15d8ff74e0e3a9523bf8708" - integrity sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg== - dependencies: - callsites "^3.1.0" - -parse-bmfont-ascii@^1.0.3: - version "1.0.6" - resolved "https://registry.yarnpkg.com/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz#11ac3c3ff58f7c2020ab22769079108d4dfa0285" - integrity sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA== - -parse-bmfont-binary@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz#d038b476d3e9dd9db1e11a0b0e53a22792b69006" - integrity sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA== - -parse-bmfont-xml@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz#015319797e3e12f9e739c4d513872cd2fa35f389" - integrity sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ== - dependencies: - xml-parse-from-string "^1.0.0" - xml2js "^0.4.5" - -parse-headers@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.5.tgz#069793f9356a54008571eb7f9761153e6c770da9" - integrity sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA== - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parse-json@^5.0.0, parse-json@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - 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" - -parse5@*, parse5@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" - integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== - dependencies: - entities "^4.4.0" - -parse5@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-exists@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-5.0.0.tgz#a6aad9489200b21fab31e49cf09277e5116fb9e7" - integrity sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-key@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" - integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -peek-readable@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-4.1.0.tgz#4ece1111bf5c2ad8867c314c81356847e8a62e72" - integrity sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg== - -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== - -phin@^2.9.1: - version "2.9.3" - resolved "https://registry.yarnpkg.com/phin/-/phin-2.9.3.tgz#f9b6ac10a035636fb65dfc576aaaa17b8743125c" - integrity sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA== - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pidtree@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" - integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - -pino-abstract-transport@^1.0.0, pino-abstract-transport@v1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.1.0.tgz#083d98f966262164504afb989bccd05f665937a8" - integrity sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA== - dependencies: - readable-stream "^4.0.0" - split2 "^4.0.0" - -pino-http@^5.3.0: - version "5.8.0" - resolved "https://registry.yarnpkg.com/pino-http/-/pino-http-5.8.0.tgz#6e688fd5f965c5b6991f340eb660ea2927be9aa7" - integrity sha512-YwXiyRb9y0WCD1P9PcxuJuh3Dc5qmXde/paJE86UGYRdiFOi828hR9iUGmk5gaw6NBT9gLtKANOHFimvh19U5w== - dependencies: - fast-url-parser "^1.1.3" - pino "^6.13.0" - pino-std-serializers "^4.0.0" - -pino-pretty@*: - version "10.2.0" - resolved "https://registry.yarnpkg.com/pino-pretty/-/pino-pretty-10.2.0.tgz#c674a153e15c08d7032a826d0051d786feace1d9" - integrity sha512-tRvpyEmGtc2D+Lr3FulIZ+R1baggQ4S3xD2Ar93KixFEDx6SEAUP3W5aYuEw1C73d6ROrNcB2IXLteW8itlwhA== - dependencies: - colorette "^2.0.7" - dateformat "^4.6.3" - fast-copy "^3.0.0" - fast-safe-stringify "^2.1.1" - help-me "^4.0.1" - joycon "^3.1.1" - minimist "^1.2.6" - on-exit-leak-free "^2.1.0" - pino-abstract-transport "^1.0.0" - pump "^3.0.0" - readable-stream "^4.0.0" - secure-json-parse "^2.4.0" - sonic-boom "^3.0.0" - strip-json-comments "^3.1.1" - -pino-pretty@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/pino-pretty/-/pino-pretty-6.0.0.tgz#4d7ac8528ad74d90040082816202bb7d48eb1c95" - integrity sha512-jyeR2fXXWc68st1DTTM5NhkHlx8p+1fKZMfm84Jwq+jSw08IwAjNaZBZR6ts69hhPOfOjg/NiE1HYW7vBRPL3A== - dependencies: - "@hapi/bourne" "^2.0.0" - args "^5.0.1" - colorette "^1.3.0" - dateformat "^4.5.1" - fast-safe-stringify "^2.0.7" - jmespath "^0.15.0" - joycon "^3.0.0" - pump "^3.0.0" - readable-stream "^3.6.0" - rfdc "^1.3.0" - split2 "^3.1.1" - strip-json-comments "^3.1.1" - -pino-std-serializers@*, pino-std-serializers@^6.0.0: - version "6.2.2" - resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz#d9a9b5f2b9a402486a5fc4db0a737570a860aab3" - integrity sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA== - -pino-std-serializers@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz#b56487c402d882eb96cd67c257868016b61ad671" - integrity sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg== - -pino-std-serializers@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz#1791ccd2539c091ae49ce9993205e2cd5dbba1e2" - integrity sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q== - -pino@^6.13.0, pino@^6.7.0: - version "6.14.0" - resolved "https://registry.yarnpkg.com/pino/-/pino-6.14.0.tgz#b745ea87a99a6c4c9b374e4f29ca7910d4c69f78" - integrity sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg== - dependencies: - fast-redact "^3.0.0" - fast-safe-stringify "^2.0.8" - flatstr "^1.0.12" - pino-std-serializers "^3.1.0" - process-warning "^1.0.0" - quick-format-unescaped "^4.0.3" - sonic-boom "^1.0.2" - -pino@^8.5.0: - version "8.15.1" - resolved "https://registry.yarnpkg.com/pino/-/pino-8.15.1.tgz#04b815ff7aa4e46b1bbab88d8010aaa2b17eaba4" - integrity sha512-Cp4QzUQrvWCRJaQ8Lzv0mJzXVk4z2jlq8JNKMGaixC2Pz5L4l2p95TkuRvYbrEbe85NQsDKrAd4zalf7Ml6WiA== - dependencies: - atomic-sleep "^1.0.0" - fast-redact "^3.1.1" - on-exit-leak-free "^2.1.0" - pino-abstract-transport v1.1.0 - pino-std-serializers "^6.0.0" - process-warning "^2.0.0" - quick-format-unescaped "^4.0.3" - real-require "^0.2.0" - safe-stable-stringify "^2.3.1" - sonic-boom "^3.1.0" - thread-stream "^2.0.0" - -pirates@^4.0.1: - version "4.0.6" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" - integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== - -pixelmatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-4.0.2.tgz#8f47dcec5011b477b67db03c243bc1f3085e8854" - integrity sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA== - dependencies: - pngjs "^3.0.0" - -pkg-conf@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-3.1.0.tgz#d9f9c75ea1bae0e77938cde045b276dac7cc69ae" - integrity sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ== - dependencies: - find-up "^3.0.0" - load-json-file "^5.2.0" - -pkg-dir@4.2.0, pkg-dir@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -pngjs@^3.0.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" - integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== - -pngjs@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-6.0.0.tgz#ca9e5d2aa48db0228a52c419c3308e87720da821" - integrity sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg== - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prettier@^2.7.1: - version "2.8.8" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" - integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== - -pretty-format@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" - integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== - dependencies: - "@jest/types" "^26.6.2" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^17.0.1" - -pretty-format@^28.0.0, pretty-format@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.3.tgz#c9fba8cedf99ce50963a11b27d982a9ae90970d5" - integrity sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q== - dependencies: - "@jest/schemas" "^28.1.3" - ansi-regex "^5.0.1" - ansi-styles "^5.0.0" - react-is "^18.0.0" - -probot@^12.1.1, probot@^12.2.1, probot@^12.2.4: - version "12.3.1" - resolved "https://registry.yarnpkg.com/probot/-/probot-12.3.1.tgz#6a19f3faf941978df04afb2dd3f5f65422450c03" - integrity sha512-ECSgycmAC0ILEK6cOa+x3QPufP5JybsuohOFCYr3glQU5SkbmypZJE/Sfio9mxAFHK5LCXveIDsfZCxf6ck4JA== - dependencies: - "@octokit/core" "^3.2.4" - "@octokit/plugin-enterprise-compatibility" "^1.2.8" - "@octokit/plugin-paginate-rest" "^2.6.2" - "@octokit/plugin-rest-endpoint-methods" "^5.0.1" - "@octokit/plugin-retry" "^3.0.6" - "@octokit/plugin-throttling" "^3.3.4" - "@octokit/types" "^8.0.0" - "@octokit/webhooks" "^9.8.4" - "@probot/get-private-key" "^1.1.0" - "@probot/octokit-plugin-config" "^1.0.0" - "@probot/pino" "^2.2.0" - "@types/express" "^4.17.9" - "@types/ioredis" "^4.27.1" - "@types/pino" "^6.3.4" - "@types/pino-http" "^5.0.6" - commander "^6.2.0" - deepmerge "^4.2.2" - deprecation "^2.3.1" - dotenv "^8.2.0" - eventsource "^2.0.2" - express "^4.17.1" - express-handlebars "^6.0.3" - ioredis "^4.27.8" - js-yaml "^3.14.1" - lru-cache "^6.0.0" - octokit-auth-probot "^1.2.2" - pino "^6.7.0" - pino-http "^5.3.0" - pkg-conf "^3.1.0" - resolve "^1.19.0" - semver "^7.3.4" - update-dotenv "^1.1.1" - uuid "^8.3.2" - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -process-warning@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-1.0.0.tgz#980a0b25dc38cd6034181be4b7726d89066b4616" - integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q== - -process-warning@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-2.2.0.tgz#008ec76b579820a8e5c35d81960525ca64feb626" - integrity sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg== - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== - -progress@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -prompts@^2.0.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" - integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - -propagate@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/propagate/-/propagate-2.0.1.tgz#40cdedab18085c792334e64f0ac17256d38f9a45" - integrity sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag== - -proxy-addr@~2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - -proxy-from-env@1.1.0, proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - -psl@^1.1.33: - version "1.9.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" - integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== - -pstree.remy@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" - integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -punycode@^1.3.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== - -punycode@^2.1.0, punycode@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" - integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== - -puppeteer-cluster@^0.23.0: - version "0.23.0" - resolved "https://registry.yarnpkg.com/puppeteer-cluster/-/puppeteer-cluster-0.23.0.tgz#da3f5c07de8a3069962bd9af6ee1767ba08fdbaf" - integrity sha512-108terIWDzPrQopmoYSPd5yDoy3FGJ2dNnoGMkGYPs6xtkdhgaECwpfZkzaRToMQPZibUOz0/dSSGgPEdXEhkQ== - dependencies: - debug "^4.3.3" - -puppeteer@^15.3.0: - version "15.5.0" - resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-15.5.0.tgz#446e01547ba0f47c37ac2148e5333433b4ecb371" - integrity sha512-+vZPU8iBSdCx1Kn5hHas80fyo0TiVyMeqLGv/1dygX2HKhAZjO9YThadbRTCoTYq0yWw+w/CysldPsEekDtjDQ== - dependencies: - cross-fetch "3.1.5" - debug "4.3.4" - devtools-protocol "0.0.1019158" - extract-zip "2.0.1" - https-proxy-agent "5.0.1" - pkg-dir "4.2.0" - progress "2.0.3" - proxy-from-env "1.1.0" - rimraf "3.0.2" - tar-fs "2.1.1" - unbzip2-stream "1.4.3" - ws "8.8.0" - -qs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== - dependencies: - side-channel "^1.0.4" - -qs@^6.10.3, qs@^6.11.0: - version "6.11.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" - integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== - dependencies: - side-channel "^1.0.4" - -querystringify@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" - integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -quick-format-unescaped@^4.0.3: - version "4.0.4" - resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" - integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== - -quick-lru@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" - integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== - -range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" - integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - -react-is@^17.0.1: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== - -react-is@^18.0.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== - -read-cmd-shim@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz#640a08b473a49043e394ae0c7a34dd822c73b9bb" - integrity sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q== - -read-pkg-up@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" - integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== - dependencies: - find-up "^4.1.0" - read-pkg "^5.2.0" - type-fest "^0.8.1" - -read-pkg@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" - -readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@^4.0.0: - version "4.4.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.4.2.tgz#e6aced27ad3b9d726d8308515b9a1b98dc1b9d13" - integrity sha512-Lk/fICSyIhodxy1IDK2HazkeGjSmezAWX2egdtJnYhtzKEsBPJowlI6F6LPb5tqIQILrMbx22S5o3GuJavPusA== - dependencies: - abort-controller "^3.0.0" - buffer "^6.0.3" - events "^3.3.0" - process "^0.11.10" - string_decoder "^1.3.0" - -readable-stream@~1.0.31: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@~2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" - 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" - -readable-web-to-node-stream@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz#5d52bb5df7b54861fd48d015e93a2cb87b3ee0bb" - integrity sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw== - dependencies: - readable-stream "^3.6.0" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -real-require@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78" - integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg== - -redent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" - integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== - dependencies: - indent-string "^4.0.0" - strip-indent "^3.0.0" - -redis-commands@1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" - integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== - -redis-errors@^1.0.0, redis-errors@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" - integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w== - -redis-parser@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" - integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A== - dependencies: - redis-errors "^1.0.0" - -regenerator-runtime@^0.13.3: - version "0.13.11" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw== - -repeat-element@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" - integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== - -resolve-cwd@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" - integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== - dependencies: - resolve-from "^5.0.0" - -resolve-from@5.0.0, resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-global@1.0.0, resolve-global@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/resolve-global/-/resolve-global-1.0.0.tgz#a2a79df4af2ca3f49bf77ef9ddacd322dad19255" - integrity sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw== - dependencies: - global-dirs "^0.1.1" - -resolve-pkg-maps@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" - integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== - -resolve@^1.10.0, resolve@^1.18.1, resolve@^1.19.0: - version "1.22.4" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" - integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -restore-cursor@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9" - integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rfdc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== - -rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rsvp@^4.8.4: - version "4.8.5" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" - integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-compare@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/safe-compare/-/safe-compare-1.1.4.tgz#5e0128538a82820e2e9250cd78e45da6786ba593" - integrity sha512-b9wZ986HHCo/HbKrRpBJb2kqXMK9CEWIE1egeEvZsYn69ay3kdfl9nG3RyOcR+jInTDf7a86WQ1d4VJX7goSSQ== - dependencies: - buffer-alloc "^1.2.0" - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg== - dependencies: - ret "~0.1.10" - -safe-stable-stringify@^2.3.1: - version "2.4.3" - resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" - integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== - -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sandwich-stream@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/sandwich-stream/-/sandwich-stream-2.0.2.tgz#6d1feb6cf7e9fe9fadb41513459a72c2e84000fa" - integrity sha512-jLYV0DORrzY3xaz/S9ydJL6Iz7essZeAfnAavsJ+zsJGZ1MOnsS52yRjU3uF3pJa/lla7+wisp//fxOwOH8SKQ== - -sane@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" - integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== - dependencies: - "@cnakazawa/watch" "^1.0.3" - anymatch "^2.0.0" - capture-exit "^2.0.0" - exec-sh "^0.3.2" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - -sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -saxes@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" - integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== - dependencies: - xmlchars "^2.2.0" - -scrypt-js@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" - integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== - -secure-json-parse@^2.4.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz#5a5f9cd6ae47df23dba3151edd06855d47e09862" - integrity sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw== - -"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.7.1: - version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - -semver@7.5.4, semver@7.x, semver@^7.3.2, semver@^7.3.4, semver@^7.3.7, semver@^7.5.3, semver@^7.5.4: - version "7.5.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== - dependencies: - lru-cache "^6.0.0" - -semver@^6.3.0, semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@~7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== - dependencies: - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "2.0.0" - mime "1.6.0" - ms "2.1.3" - on-finished "2.4.1" - range-parser "~1.2.1" - statuses "2.0.1" - -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.18.0" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== - -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== - dependencies: - shebang-regex "^1.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shellwords@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== - -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -signal-exit@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" - integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== - -simple-update-notifier@^1.0.7: - version "1.1.0" - resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz#67694c121de354af592b347cdba798463ed49c82" - integrity sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg== - dependencies: - semver "~7.0.0" - -sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slice-ansi@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" - integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== - dependencies: - ansi-styles "^6.0.0" - is-fullwidth-code-point "^4.0.0" - -smee-client@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/smee-client/-/smee-client-1.2.3.tgz#a0ef5e86e3640870f19f3953aaf228fa478b082c" - integrity sha512-uDrU8u9/Ln7aRXyzGHgVaNUS8onHZZeSwQjCdkMoSL7U85xI+l+Y2NgjibkMJAyXkW7IAbb8rw9RMHIjS6lAwA== - dependencies: - commander "^2.19.0" - eventsource "^1.1.0" - morgan "^1.9.1" - superagent "^7.1.3" - validator "^13.7.0" - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -sonic-boom@^1.0.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e" - integrity sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg== - dependencies: - atomic-sleep "^1.0.0" - flatstr "^1.0.12" - -sonic-boom@^2.1.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-2.8.0.tgz#c1def62a77425090e6ad7516aad8eb402e047611" - integrity sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg== - dependencies: - atomic-sleep "^1.0.0" - -sonic-boom@^3.0.0, sonic-boom@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-3.3.0.tgz#cffab6dafee3b2bcb88d08d589394198bee1838c" - integrity sha512-LYxp34KlZ1a2Jb8ZQgFCK3niIHzibdwtwNUWKg0qQRzsDoJ3Gfgkf8KdBTFU3SkejDEIlWwnSnpVdOZIhFMl/g== - dependencies: - atomic-sleep "^1.0.0" - -source-map-resolve@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@^0.5.21, source-map-support@^0.5.6: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" - integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== - -source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@^0.7.3: - version "0.7.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" - integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== - -spdx-correct@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" - integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.13" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz#7189a474c46f8d47c7b0da4b987bb45e908bd2d5" - integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w== - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - -split2@^3.0.0, split2@^3.1.1, split2@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" - integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== - dependencies: - readable-stream "^3.0.0" - -split2@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" - integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== - -stack-utils@^2.0.2, stack-utils@^2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" - integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== - dependencies: - escape-string-regexp "^2.0.0" - -standard-as-callback@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" - integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g== - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -statuses@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - -string-argv@0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" - integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== - -string-length@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" - integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== - dependencies: - char-regex "^1.0.2" - strip-ansi "^6.0.0" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^5.0.0, string-width@^5.0.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - -string_decoder@^1.1.1, string_decoder@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^7.0.1, strip-ansi@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" - integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== - dependencies: - ansi-regex "^6.0.1" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== - -strip-bom@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" - integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q== - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-final-newline@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" - integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== - -strip-indent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" - integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== - dependencies: - min-indent "^1.0.0" - -strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -strtok3@^6.2.4: - version "6.3.0" - resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-6.3.0.tgz#358b80ffe6d5d5620e19a073aa78ce947a90f9a0" - integrity sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw== - dependencies: - "@tokenizer/token" "^0.3.0" - peek-readable "^4.1.0" - -supabase@^1.38.1: - version "1.93.0" - resolved "https://registry.yarnpkg.com/supabase/-/supabase-1.93.0.tgz#35bd2706120379c7151622c548bdf95663b05e2f" - integrity sha512-7VKWPVy1QSnBcx/ubKIGFOWw9LjL6C1sMTh0d+ox0TP69+KhzphlA4Z/iFPvC6x9gUwhe9UTI0AdqJYsIwrPEA== - dependencies: - bin-links "^4.0.1" - node-fetch "^3.2.10" - tar "6.1.15" - -superagent@^7.1.3: - version "7.1.6" - resolved "https://registry.yarnpkg.com/superagent/-/superagent-7.1.6.tgz#64f303ed4e4aba1e9da319f134107a54cacdc9c6" - integrity sha512-gZkVCQR1gy/oUXr+kxJMLDjla434KmSOKbx5iGD30Ql+AkJQ/YlPKECJy2nhqOsHLjGHzoDTXNSjhnvWhzKk7g== - dependencies: - component-emitter "^1.3.0" - cookiejar "^2.1.3" - debug "^4.3.4" - fast-safe-stringify "^2.1.1" - form-data "^4.0.0" - formidable "^2.0.1" - methods "^1.1.2" - mime "2.6.0" - qs "^6.10.3" - readable-stream "^3.6.0" - semver "^7.3.7" - -supports-color@^5.3.0, supports-color@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.0.0, supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-hyperlinks@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" - integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== - dependencies: - has-flag "^4.0.0" - supports-color "^7.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -symbol-tree@^3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - -tar-fs@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" - integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== - dependencies: - chownr "^1.1.1" - mkdirp-classic "^0.5.2" - pump "^3.0.0" - tar-stream "^2.1.4" - -tar-stream@^2.1.4: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" - integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== - dependencies: - bl "^4.0.3" - end-of-stream "^1.4.1" - fs-constants "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.1.1" - -tar@6.1.15: - version "6.1.15" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.15.tgz#c9738b0b98845a3b344d334b8fa3041aaba53a69" - integrity sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A== - 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" - -telegraf@^4.11.2: - version "4.13.1" - resolved "https://registry.yarnpkg.com/telegraf/-/telegraf-4.13.1.tgz#ad0b6df452aa133bf6561b4a182bdedb558046b6" - integrity sha512-WXITwqE3ivqDqjHFxj94xaQhHddldBZdE2g/hRJXyCMTkwZYw69q9I7La7nsDpsHLn5ADSQlGv0KAbwFkFpmlA== - dependencies: - "@telegraf/types" "^6.8.1" - abort-controller "^3.0.0" - debug "^4.3.4" - mri "^1.2.0" - node-fetch "^2.6.8" - p-timeout "^4.1.0" - safe-compare "^1.1.4" - sandwich-stream "^2.0.2" - -terminal-link@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" - integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== - dependencies: - ansi-escapes "^4.2.1" - supports-hyperlinks "^2.0.0" - -test-exclude@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" - integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== - dependencies: - "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" - -text-extensions@^1.0.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" - integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== - -thread-stream@^2.0.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-2.4.0.tgz#5def29598d1d4171ba3bace7e023a71d87d99c07" - integrity sha512-xZYtOtmnA63zj04Q+F9bdEay5r47bvpo1CaNqsKi7TpoJHcotUez8Fkfo2RJWpW91lnnaApdpRbVwCWsy+ifcw== - dependencies: - real-require "^0.2.0" - -throat@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" - integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== - -through2@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -through2@^4.0.0, through2@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" - integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== - dependencies: - readable-stream "3" - -"through@>=2.2.7 <3", through@^2.3.8: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - -timm@^1.6.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/timm/-/timm-1.7.1.tgz#96bab60c7d45b5a10a8a4d0f0117c6b7e5aff76f" - integrity sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw== - -tiny-invariant@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" - integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== - -tinycolor2@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e" - integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw== - -tmpl@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" - integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg== - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg== - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - -token-types@^4.1.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/token-types/-/token-types-4.2.1.tgz#0f897f03665846982806e138977dbe72d44df753" - integrity sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ== - dependencies: - "@tokenizer/token" "^0.3.0" - ieee754 "^1.2.1" - -touch@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" - integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== - dependencies: - nopt "~1.0.10" - -tough-cookie@^4.0.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" - integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.2.0" - url-parse "^1.5.3" - -tr46@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" - integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== - dependencies: - punycode "^2.1.1" - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -trim-newlines@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" - integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== - -ts-jest@^26.4.4: - version "26.5.6" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35" - integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA== - dependencies: - bs-logger "0.x" - buffer-from "1.x" - fast-json-stable-stringify "2.x" - jest-util "^26.1.0" - json5 "2.x" - lodash "4.x" - make-error "1.x" - mkdirp "1.x" - semver "7.x" - yargs-parser "20.x" - -ts-node@^10.8.1: - version "10.9.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" - integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - -tslib@^1.8.1, tslib@^1.9.3: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - -tsx@^3.12.7: - version "3.12.8" - resolved "https://registry.yarnpkg.com/tsx/-/tsx-3.12.8.tgz#e9ec95c6b116e28f0187467f839029a3ce17a851" - integrity sha512-Lt9KYaRGF023tlLInPj8rgHwsZU8qWLBj4iRXNWxTfjIkU7canGL806AqKear1j722plHuiYNcL2ZCo6uS9UJA== - dependencies: - "@esbuild-kit/cjs-loader" "^2.4.2" - "@esbuild-kit/core-utils" "^3.2.2" - "@esbuild-kit/esm-loader" "^2.5.5" - optionalDependencies: - fsevents "~2.3.2" - -tunnel@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" - integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-detect@4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -type-fest@^0.18.0: - version "0.18.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" - integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -type-fest@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1" - integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ== - -type-fest@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -type-fest@^1.0.1, type-fest@^1.0.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" - integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== - -type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -type@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" - integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== - -type@^2.7.2: - version "2.7.2" - resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" - integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - -"typescript@^4.6.4 || ^5.0.0": - version "5.2.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" - integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== - -typescript@^4.9.5: - version "4.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" - integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== - -uglify-js@^3.1.4: - version "3.17.4" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" - integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== - -unbzip2-stream@1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" - integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== - dependencies: - buffer "^5.2.1" - through "^2.3.8" - -undefsafe@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" - integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== - -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - -unique-string@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-3.0.0.tgz#84a1c377aff5fd7a8bc6b55d8244b2bd90d75b9a" - integrity sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ== - dependencies: - crypto-random-string "^4.0.0" - -universal-github-app-jwt@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/universal-github-app-jwt/-/universal-github-app-jwt-1.1.1.tgz#d57cee49020662a95ca750a057e758a1a7190e6e" - integrity sha512-G33RTLrIBMFmlDV4u4CBF7dh71eWwykck4XgaxaIVeZKOYZRAAxvcGMRFTUclVY6xoUPQvO4Ne5wKGxYm/Yy9w== - dependencies: - "@types/jsonwebtoken" "^9.0.0" - jsonwebtoken "^9.0.0" - -universal-user-agent@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" - integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== - -universalify@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" - integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== - -universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ== - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -untildify@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" - integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== - -update-browserslist-db@^1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" - integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - -update-dotenv@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/update-dotenv/-/update-dotenv-1.1.1.tgz#17146f302f216c3c92419d5a327a45be910050ca" - integrity sha512-3cIC18In/t0X/yH793c00qqxcKD8jVCgNOPif/fGQkFpYMGecM9YAc+kaAKXuZsM2dE9I9wFI7KvAuNX22SGMQ== - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== - -url-parse@^1.5.3: - version "1.5.10" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" - integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -utf-8-validate@^5.0.2: - version "5.0.10" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.10.tgz#d7d10ea39318171ca982718b6b96a8d2442571a2" - integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== - dependencies: - node-gyp-build "^4.3.0" - -utif2@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/utif2/-/utif2-4.1.0.tgz#e768d37bd619b995d56d9780b5d2b4611a3d932b" - integrity sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w== - dependencies: - pako "^1.0.11" - -util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== - -uuid@^8.3.0, uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -v8-compile-cache-lib@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - -v8-to-istanbul@^7.0.0: - version "7.1.2" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz#30898d1a7fa0c84d225a2c1434fb958f290883c1" - integrity sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - source-map "^0.7.3" - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -validator@^13.7.0: - version "13.11.0" - resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" - integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ== - -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== - -vscode-languageserver-textdocument@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz#9eae94509cbd945ea44bca8dcfe4bb0c15bb3ac0" - integrity sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q== - -vscode-uri@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.7.tgz#6d19fef387ee6b46c479e5fb00870e15e58c1eb8" - integrity sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA== - -w3c-hr-time@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - dependencies: - browser-process-hrtime "^1.0.0" - -w3c-xmlserializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" - integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== - dependencies: - xml-name-validator "^3.0.0" - -walker@^1.0.7, walker@~1.0.5: - version "1.0.8" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" - integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== - dependencies: - makeerror "1.0.12" - -web-streams-polyfill@4.0.0-beta.3: - version "4.0.0-beta.3" - resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz#2898486b74f5156095e473efe989dcf185047a38" - integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug== - -web-streams-polyfill@^3.0.3: - version "3.2.1" - resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" - integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -webidl-conversions@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" - integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== - -webidl-conversions@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" - integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== - -websocket@^1.0.34: - version "1.0.34" - resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111" - integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ== - dependencies: - bufferutil "^4.0.1" - debug "^2.2.0" - es5-ext "^0.10.50" - typedarray-to-buffer "^3.1.5" - utf-8-validate "^5.0.2" - yaeti "^0.0.6" - -whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== - dependencies: - iconv-lite "0.4.24" - -whatwg-fetch@^3.4.1: - version "3.6.18" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.18.tgz#2f640cdee315abced7daeaed2309abd1e44e62d4" - integrity sha512-ltN7j66EneWn5TFDO4L9inYC1D+Czsxlrw2SalgjMmEMkLfA5SIZxEFdE6QtHFiiM6Q7WL32c7AkI3w6yxM84Q== - -whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -whatwg-url@^8.0.0, whatwg-url@^8.5.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" - integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== - dependencies: - lodash "^4.7.0" - tr46 "^2.1.0" - webidl-conversions "^6.1.0" - -which-module@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" - integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== - -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.1, which@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== - -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^8.0.1, wrap-ansi@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" - integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== - dependencies: - ansi-styles "^6.1.0" - string-width "^5.0.1" - strip-ansi "^7.0.1" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - -write-file-atomic@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz#68df4717c55c6fa4281a7860b4c2ba0a6d2b11e7" - integrity sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw== - dependencies: - imurmurhash "^0.1.4" - signal-exit "^4.0.1" - -ws@7.4.6: - version "7.4.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" - integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== - -ws@8.8.0: - version "8.8.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.8.0.tgz#8e71c75e2f6348dbf8d78005107297056cb77769" - integrity sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ== - -ws@^7.4.6: - version "7.5.9" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== - -xdg-basedir@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-5.1.0.tgz#1efba19425e73be1bc6f2a6ceb52a3d2c884c0c9" - integrity sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ== - -xhr@^2.0.1: - version "2.6.0" - resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" - integrity sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA== - dependencies: - global "~4.4.0" - is-function "^1.0.1" - parse-headers "^2.0.0" - xtend "^4.0.0" - -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - -xml-parse-from-string@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" - integrity sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g== - -xml2js@^0.4.5: - version "0.4.23" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" - integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - -xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== - -xmlchars@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== - -xtend@^4.0.0, xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -y18n@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yaeti@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" - integrity sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug== - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml@2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b" - integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== - -yaml@^2.2.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.2.tgz#f522db4313c671a0ca963a75670f1c12ea909144" - integrity sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg== - -yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.3: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -yargs-parser@^18.1.2: - version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^21.1.1: - version "21.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== - -yargs@^15.4.1: - version "15.4.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" - integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== - dependencies: - cliui "^6.0.0" - decamelize "^1.2.0" - find-up "^4.1.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^4.2.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^18.1.2" - -yargs@^16.1.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - 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" - -yargs@^17.0.0: - version "17.7.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" - integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== - 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" - -yauzl@^2.10.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -yocto-queue@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" - integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==