diff --git a/.gitignore b/.gitignore index 07aad6c..a8d3c4a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ config.json +.*.env .env node_modules @@ -19,4 +20,6 @@ template.old.yaml coverage/ -chores.json \ No newline at end of file +chores.json + +scheduler_role.json \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e28859f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,58 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Debug weekly", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}/src/modules/jobs/weekly/debug.js", + "envFile": "${workspaceFolder}/.dev.env", + }, + { + "type": "node", + "request": "launch", + "name": "Debug daily", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}/src/modules/jobs/daily/debug.js", + "envFile": "${workspaceFolder}/.dev.env", + }, + { + "type": "node", + "request": "launch", + "name": "Debug monthly", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}/src/modules/jobs/monthly/debug.js", + "envFile": "${workspaceFolder}/.dev.env", + }, + { + "type": "node", + "request": "launch", + "name": "Debug complete", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}/src/modules/debug-commands/debug-complete.js", + "envFile": "${workspaceFolder}/.dev.env", + }, + { + "type": "node", + "request": "launch", + "name": "Debug assign", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}/src/modules/debug-commands/debug-assign.js", + "envFile": "${workspaceFolder}/.dev.env", + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 13cd9f1..c25f996 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,13 @@

+## NOTE +Best practice: make two AWS accounts and then configure each with `aws configure --profile `, then use `AWS_PROFILE=` before yarn commands, e.g. `AWS_PROFILE=cb-dev yarn setup-scheduler` + +Also, specifically for generating the SAM template, use `DEV=true yarn generate-template` for your dev environment. It will use a file called `.dev.env` in the root environment if you've created one. You can place your dev AWS credentials there. + +Make sure to slide the slider for your Discord bot under `Bot > Privileged Gateway Intents > SERVER MEMBERS INTENT` + ## Setup (instructions still in progress) 1. Create a Discord channel for the Chore Bot, and enable developer mode so you can copy IDs from Discord 2. Fill out `.example_env` and rename to `.env` @@ -18,11 +25,12 @@ 4. Run `yarn setup` 5. Modify `setup/tables/example_chores.json` as desired so it matches your chore list, then rename it to `chores.json` 6. Create an AWS account -7. Run `yarn setup-iam` (in-progress feature, use created `Bot` user for cli) -8. Run `yarn setup-scheduler` -9. Deploy with `yarn deploy` -10. Upload the initial chores data with `yarn upload-chores-list` -11. There will now be daily, weekly, and monthly scheduled jobs that will take care of all chore assignments etc., and slash commands will be registered in your Discord guild +7. Run `yarn setup-iam` (in-progress feature, use created `Bot` user for cli) +8. In the AWS console, navigate to iam/users/Bot, then create an access key for the user. Run `aws configure --profile default` and use the access key and secret access key. +9. Run `yarn setup-scheduler` +10. Deploy with `yarn deploy` +11. Upload the initial chores data with `yarn upload-chores-list` +12. There will now be daily, weekly, and monthly scheduled jobs that will take care of all chore assignments etc., and slash commands will be registered in your Discord guild ## Features diff --git a/_design/ARCHITECTURE.md b/_design/ARCHITECTURE.md index f5a2116..3b6f9ed 100644 --- a/_design/ARCHITECTURE.md +++ b/_design/ARCHITECTURE.md @@ -23,6 +23,7 @@ users displayName numCycleChores numAllTimeChores + inactive * currentChore (-> chores) chores diff --git a/deploy.sh b/deploy.sh deleted file mode 100755 index 09de505..0000000 --- a/deploy.sh +++ /dev/null @@ -1,4 +0,0 @@ -yarn -node register_commands/register.js -sam build -sam deploy \ No newline at end of file diff --git a/package.json b/package.json index 1860faa..fa6855b 100755 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "author": "moromis", "version": "0.0.1", "private": true, + "license": "./LICENSE.md", "dependencies": { "eslint-plugin-require-path-exists": "^1.1.9" }, @@ -16,16 +17,24 @@ "recursive-install": "^1.4.0" }, "scripts": { - "deploy": "./deploy.sh", + "deploy": "./scripts/deploy.sh", + "dev:deploy": "export AWS_PROFILE=cb-dev && export DEV=true && ./scripts/deploy.sh", "upload-chores-list": "cd setup/tables && node upload_chores.js", + "dev:upload-chores-list": "export AWS_PROFILE=cb-dev && cd setup/tables && node upload_chores.js", + "register-commands": "cd register_commands && node register.js", + "dev:register-commands": "export AWS_PROFILE=cb-dev && export DEV=true && cd register_commands && node register.js", "destroy": "cd scripts && ./destroy.sh", + "dev:destroy": "export AWS_PROFILE=cb-dev && cd scripts && ./destroy.sh", "test": "jest --passWithNoTests src", "test:coverage": "yarn test --config jest.config.json --no-cache", "test:badge": "yarn test:coverage && yarn make-coverage-badge --output-path ./cov-badge.svg", "generate-template": "cd setup/generate_template && yarn && node generate_template.js", "setup-scheduler": "cd setup/scheduler && ./setup_scheduler.sh", + "dev:setup-scheduler": "export AWS_PROFILE=cb-dev && export DEV=true && cd setup/scheduler && ./setup_scheduler.sh", "setup-iam": "cd setup/iam_user && ./setup_iam_user_and_policy.sh", + "dev:setup-iam": "export AWS_PROFILE=cb-dev && cd setup/iam_user && ./setup_iam_user_and_policy.sh", "setup": "yarn generate-template", - "install-deps": "yarn && node recursive-install-yarn.js --rootDir=src" + "dev:setup": "export AWS_PROFILE=cb-dev && yarn generate-template", + "install-deps": "yarn && node scripts/recursive-install-yarn.js --rootDir=src" } } \ No newline at end of file diff --git a/register_commands/register.js b/register_commands/register.js index 231a99f..5ea9b50 100644 --- a/register_commands/register.js +++ b/register_commands/register.js @@ -1,6 +1,10 @@ const dotenv = require("dotenv"); const register = require("./misc/send.js").register; -dotenv.config(); +dotenv.config({ + path: !!process.env.DEV === true ? "../.dev.env" : "../.env", +}); + +console.log("registering commands using AWS account ", process.env.AWS_ID); if (!process.env.APP_ID || !process.env.BOT_TOKEN) { throw "You must define APP_ID and BOT_TOKEN in .env file or in a command line run (e.g. APP_ID=1234 BOT_TOKEN=ABCD node register_commands/register.js)"; diff --git a/samconfig.toml b/samconfig.toml index d7897cc..b25e964 100644 --- a/samconfig.toml +++ b/samconfig.toml @@ -6,7 +6,7 @@ version = 0.1 stack_name = "sam-app" [default.build.parameters] -cached = true +cached = false parallel = true [default.deploy.parameters] diff --git a/scripts/deploy.sh b/scripts/deploy.sh new file mode 100755 index 0000000..3223273 --- /dev/null +++ b/scripts/deploy.sh @@ -0,0 +1,8 @@ +echo $DEV +echo $AWS_PROFILE +rm -rf .aws-sam +yarn +yarn generate-template +yarn register-commands +sam build +sam deploy \ No newline at end of file diff --git a/scripts/destroy.sh b/scripts/destroy.sh index cccc163..33f387e 100755 --- a/scripts/destroy.sh +++ b/scripts/destroy.sh @@ -1,3 +1,5 @@ +echo $AWS_PROFILE + # from https://stackoverflow.com/questions/1885525/how-do-i-prompt-a-user-for-confirmation-in-bash-script read -p "This will delete EVERYTHING and you will have to re-deploy. All your data will be GONE. Are you sure? (y/n)" -n 1 -r echo # (optional) move to a new line @@ -5,4 +7,7 @@ if [[ $REPLY =~ ^[Yy]$ ]] then cd .. sam delete + echo "Done with sam delete" + aws cloudformation delete-stack --stack-name sam-app + echo "Done with cloudformation delete-stack" fi \ No newline at end of file diff --git a/recursive-install-yarn.js b/scripts/recursive-install-yarn.js similarity index 100% rename from recursive-install-yarn.js rename to scripts/recursive-install-yarn.js diff --git a/setup/generate_template/generate_template.js b/setup/generate_template/generate_template.js index 0a9c5b4..3c60540 100644 --- a/setup/generate_template/generate_template.js +++ b/setup/generate_template/generate_template.js @@ -5,13 +5,18 @@ const fs = require("fs"); const { create_template_yaml_string, } = require("./create_template_yaml_string"); -dotenv.config({ path: "../../.env" }); +dotenv.config({ + path: !!process.env.DEV === true ? "../../.dev.env" : "../../.env", +}); + +console.log("generating template using AWS account ", process.env.AWS_ID); if ( !process.env.PUBLIC_KEY || !process.env.CHANNEL_ID || !process.env.BOT_TOKEN || - !process.env.GUILD_ID + !process.env.GUILD_ID || + !process.env.AWS_ID ) { throw "You must define all variables in the .env file (see readme for more details)"; } diff --git a/setup/scheduler/create_scheduler_role.js b/setup/scheduler/create_scheduler_role.js new file mode 100644 index 0000000..5764074 --- /dev/null +++ b/setup/scheduler/create_scheduler_role.js @@ -0,0 +1,30 @@ +const dotenv = require("dotenv"); +const path = require("path"); +const fs = require("fs"); +const { create_template_string } = require("./scheduler_role_template"); +dotenv.config({ + path: !!process.env.DEV === true ? "../../.dev.env" : "../../.env", +}); + +console.log( + "generating scheduler role json using AWS account ", + process.env.AWS_ID +); + +if (!process.env.AWS_ID) { + throw "You must define all variables in the .env file (see readme for more details)"; +} + +const main = () => { + const template = create_template_string(); + + fs.writeFileSync( + path.join(__dirname, "scheduler_role.json"), + template, + "utf-8" + ); + console.log("File scheduler_role.json generated successfully."); + return; +}; + +main(); diff --git a/setup/scheduler/package.json b/setup/scheduler/package.json new file mode 100644 index 0000000..c8bb776 --- /dev/null +++ b/setup/scheduler/package.json @@ -0,0 +1,10 @@ +{ + "name": "scheduler", + "version": "1.0.0", + "main": "index.js", + "author": "Kevin Ulrich", + "license": "MIT", + "dependencies": { + "dotenv": "^16.4.5" + } +} diff --git a/setup/scheduler/scheduler_role.json b/setup/scheduler/scheduler_role_template.js similarity index 59% rename from setup/scheduler/scheduler_role.json rename to setup/scheduler/scheduler_role_template.js index f618719..ed25693 100644 --- a/setup/scheduler/scheduler_role.json +++ b/setup/scheduler/scheduler_role_template.js @@ -1,4 +1,4 @@ -{ +exports.create_template_string = () => `{ "Version": "2012-10-17", "Statement": [ { @@ -9,10 +9,10 @@ "Action": "sts:AssumeRole", "Condition": { "StringEquals": { - "aws:SourceAccount": "ACCOUNT_ID", - "aws:SourceArn": "COPY_FROM_SCHEDULER_GROUP_PAGE" + "aws:SourceAccount": "${process.env.AWS_ID}", + "aws:SourceArn": "arn:aws:scheduler:us-east-2:${process.env.AWS_ID}:schedule-group/default" } } } ] -} \ No newline at end of file +}`; diff --git a/setup/scheduler/setup_scheduler.sh b/setup/scheduler/setup_scheduler.sh index 053200d..02423f2 100755 --- a/setup/scheduler/setup_scheduler.sh +++ b/setup/scheduler/setup_scheduler.sh @@ -1,5 +1,10 @@ user_id=$(aws sts get-caller-identity --query 'Account' --output text) +echo $DEV +echo $AWS_PROFILE +echo $user_id +yarn +node create_scheduler_role.js aws iam create-role --role-name SchedulerExecutionRole --assume-role-policy-document file://scheduler_role.json aws iam create-policy --policy-name SchedulerPolicy --policy-document file://scheduler_policy.json aws iam attach-role-policy --policy-arn arn:aws:iam::${user_id}:policy/SchedulerPolicy --role-name SchedulerExecutionRole \ No newline at end of file diff --git a/setup/scheduler/yarn.lock b/setup/scheduler/yarn.lock new file mode 100644 index 0000000..cbc9914 --- /dev/null +++ b/setup/scheduler/yarn.lock @@ -0,0 +1,8 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +dotenv@^16.4.5: + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== diff --git a/src/helpers/getChoreMessage.js b/src/helpers/getChoreMessage.js index 8404cfe..4541fb7 100644 --- a/src/helpers/getChoreMessage.js +++ b/src/helpers/getChoreMessage.js @@ -1,2 +1,6 @@ -exports.getChoreMessage = (chore) => - `**Chore**: ${chore.displayName}\n**Description**: ${chore.description}`; +exports.getChoreMessage = (chore) => { + if (!chore || !chore.displayName || !chore.description) { + return "Chore not found"; + } + return `**Chore**: ${chore.displayName}\n**Description**: ${chore.description}\n**Reviewer**: <@${chore.reviewer}>`; +}; diff --git a/src/helpers/getChoreMessage.test.js b/src/helpers/getChoreMessage.test.js index 2236b9e..8a5164b 100644 --- a/src/helpers/getChoreMessage.test.js +++ b/src/helpers/getChoreMessage.test.js @@ -1,8 +1,8 @@ const { getChoreMessage } = require("./getChoreMessage"); describe("getChoreMessage", () => { - test("calling chore message with no params should throw an error", () => { - expect(() => getChoreMessage()).toThrow(); + test("calling chore message with no params should let you know the chore wasn't found", () => { + expect(getChoreMessage()).toBe("Chore not found"); }); test("calling chore message with a chore object should return a string", () => { diff --git a/src/modules/commands/assign.js b/src/modules/commands/assign.js index 7ecf4c8..aef45c1 100644 --- a/src/modules/commands/assign.js +++ b/src/modules/commands/assign.js @@ -6,7 +6,7 @@ const { removeRandomFromList, } = require("../../helpers/removeRandomFromList.js"); const { getChoreMessage } = require("../../helpers/getChoreMessage.js"); -const { addNewUsers } = require("../../services/addNewUsers.js"); +const { updateUsers } = require("../../services/updateUsers.js"); const { Client, GatewayIntentBits } = require("discord.js"); const globalHandler = require("../handler.js").globalHandler; @@ -27,7 +27,7 @@ const _action = async (body) => { await client.login(process.env.BOT_TOKEN); const userId = body.member.user.id; - const allUsers = await addNewUsers(client); + const allUsers = await updateUsers(client); // TODO: maybe we should actually only update users in weekly and maybe monthly? const user = allUsers.find((u) => u.id === userId); if (user.hasOwnProperty("currentChore")) { // IMPORTANT: destroy the discord.js client, otherwise the application hangs @@ -38,7 +38,7 @@ const _action = async (body) => { } let newChore; - const choresToPickFrom = await services.getTodoChores(); + let choresToPickFrom = await services.getTodoChores(); if (choresToPickFrom.length === 0) { // TODO: big deal here! celebrate all chores being done! await services.unassignCompletedChores(); @@ -65,14 +65,16 @@ const _action = async (body) => { const reviewer = _.cloneDeep(removeRandomFromList(potentialReviewers)); if (newChore) { - await db.put(TABLES.CHORES, { + newChore = { ...newChore, - user: _.cloneDeep(user), - reviewer, + user: user.id, + reviewer: reviewer.id, status: CHORE_STATES.ASSIGNED, - }); + }; + await db.put(TABLES.CHORES, newChore); await db.put(TABLES.USERS, { ...user, + inactive: false, currentChore: newChore.id, }); } @@ -80,9 +82,7 @@ const _action = async (body) => { let response; if (newChore) { response = { - content: `<@${userId}> Your chore is\n${getChoreMessage( - newChore - )}\nYour reviewer is <@${reviewer.id}>`, + content: `<@${userId}> Your new chore is\n${getChoreMessage(newChore)}`, }; } else { response = { diff --git a/src/modules/commands/chore.js b/src/modules/commands/chore.js index f80fb4f..e48fb88 100644 --- a/src/modules/commands/chore.js +++ b/src/modules/commands/chore.js @@ -1,12 +1,6 @@ -const { CHORE_STATES } = require("../../constants/chores.js"); const { TABLES } = require("../../constants/tables.js"); const services = require("../../services"); -const _ = require("lodash"); -const { - removeRandomFromList, -} = require("../../helpers/removeRandomFromList.js"); const { getChoreMessage } = require("../../helpers/getChoreMessage.js"); -const { addNewUsers } = require("../../services/addNewUsers.js"); const { Client, GatewayIntentBits } = require("discord.js"); const globalHandler = require("../handler.js").globalHandler; @@ -32,11 +26,21 @@ const _action = async (body) => { chore = await services.db.getItem(TABLES.CHORES, user.currentChore); } - await services.dmUser( - client, - user.id, - `Your current chore is\n${getChoreMessage(chore)}` - ); + if (chore) { + console.log("got chore ", chore); + await services.dmUser( + client, + user.id, + `Your current chore is\n${getChoreMessage(chore)}` + ); + } else { + // IMPORTANT: destroy the discord.js client, otherwise the application hangs + await client.destroy(); + + return { + content: "Couldn't find your chore. Maybe you need to do `/assign`?", + }; + } // IMPORTANT: destroy the discord.js client, otherwise the application hangs await client.destroy(); diff --git a/src/modules/commands/complete.js b/src/modules/commands/complete.js index 4e5a368..43cc2d9 100755 --- a/src/modules/commands/complete.js +++ b/src/modules/commands/complete.js @@ -1,9 +1,11 @@ const { CHORE_STATES } = require("../../constants/chores.js"); const { TABLES } = require("../../constants/tables.js"); const { dmUser } = require("../../services/dmUser.js"); -const { getAllChores } = require("../../services/getChores.js"); +const { getChore } = require("../../services/getChores.js"); const _ = require("lodash"); const { Client, GatewayIntentBits } = require("discord.js"); +const { getChoreMessage } = require("../../helpers/getChoreMessage.js"); +const { getUser } = require("../../services/getUser.js"); const globalHandler = require("../handler.js").globalHandler; const db = require("../../services").db; @@ -14,7 +16,7 @@ const data = { description: "mark your chore as complete", }; -const action = async (body) => { +const _action = async (body) => { // Create a new client instance const client = new Client({ intents: [GatewayIntentBits.Guilds], @@ -24,17 +26,19 @@ const action = async (body) => { const userId = body.member.user.id; - const allChores = await getAllChores(); - const chore = allChores.find((c) => c?.user?.id === userId); + // const allChores = await getAllChores(); + // const chore = allChores.find((c) => c?.user?.id === userId); + const user = await getUser(userId); + const chore = await getChore(user.currentChore); if (chore) { await db.put(TABLES.CHORES, { ..._.omit(chore, ["user", "reviewer"]), status: CHORE_STATES.COMPLETE, }); await db.put(TABLES.USERS, { - ..._.omit(chore.user, ["currentChore"]), - numCycleChores: chore.user.numCycleChores + 1, - numAllTimeChores: chore.user.numAllTimeChores + 1, + ..._.omit(user, ["currentChore"]), + numCycleChores: (user?.numCycleChores || 0) + 1, + numAllTimeChores: (user?.numAllTimeChores || 0) + 1, }); } else { return { @@ -44,26 +48,25 @@ const action = async (body) => { await dmUser( client, - chore.reviewer.id, + chore.reviewer, `<@${userId}> is done with their chore. You're their reviewer, so please check their work.\n${getChoreMessage( chore )}` ); - let response = { - content: `<@${userId}> You completed your chore! :tada: Type \`/assign\` if you want another one.`, - }; - await client.destroy(); - return response; + return { + content: `<@${userId}> You completed your chore! :tada: Type \`/assign\` if you want another one.`, + }; }; function handler(event) { - globalHandler(event, action); + globalHandler(event, _action); } module.exports = { data, handler, + _action, }; diff --git a/src/modules/commands/swap.js b/src/modules/commands/swap.js index 528873e..f87c136 100644 --- a/src/modules/commands/swap.js +++ b/src/modules/commands/swap.js @@ -1,11 +1,12 @@ const { CHORE_STATES } = require("../../constants/chores.js"); const { TABLES } = require("../../constants/tables.js"); -const { getAllChores, getTodoChores } = require("../../services/getChores.js"); +const { getTodoChores, getChore } = require("../../services/getChores.js"); const _ = require("lodash"); const { removeRandomFromList, } = require("../../helpers/removeRandomFromList.js"); const { getChoreMessage } = require("../../helpers/getChoreMessage.js"); +const { getUser } = require("../../services/getUser.js"); const globalHandler = require("../handler.js").globalHandler; const db = require("../../services").db; @@ -19,8 +20,8 @@ const data = { const _action = async (body) => { const userId = body.member.user.id; - const allChores = await getAllChores(); - const oldChore = allChores.find((c) => c?.user?.id === userId); + const user = getUser(userId); + const oldChore = getChore(user.currentChore); let newChore; if (!oldChore) { return { @@ -49,9 +50,7 @@ const _action = async (body) => { let response; if (newChore) { response = { - content: `<@${userId}> Your new chore is\n${getChoreMessage( - newChore - )}\nYour reviewer is still <@${oldChore.reviewer.id}>`, + content: `<@${userId}> Your new chore is\n${getChoreMessage(newChore)}`, }; } else { response = { diff --git a/src/modules/debug-commands/debug-complete.js b/src/modules/debug-commands/debug-complete.js new file mode 100644 index 0000000..6e604f0 --- /dev/null +++ b/src/modules/debug-commands/debug-complete.js @@ -0,0 +1,14 @@ +const dotenv = require("dotenv"); +const _action = require("../commands/complete")._action; + +dotenv.config(); + +const testBody = { + member: { + user: { + id: process.env.MEMBER_ID, + }, + }, +}; + +_action(testBody); diff --git a/src/modules/jobs/daily/debug.js b/src/modules/jobs/daily/debug.js index 8df11cd..cb6d94e 100644 --- a/src/modules/jobs/daily/debug.js +++ b/src/modules/jobs/daily/debug.js @@ -1,5 +1,8 @@ const dotenv = require("dotenv"); const handler = require("./daily").handler; -dotenv.config({ path: "../../../../.env" }); +dotenv.config({ + path: + !!process.env.DEV === true ? "../../../../.dev.env" : "../../../../.env", +}); handler(); diff --git a/src/modules/jobs/monthly/debug.js b/src/modules/jobs/monthly/debug.js index b9a4f99..d07f06c 100644 --- a/src/modules/jobs/monthly/debug.js +++ b/src/modules/jobs/monthly/debug.js @@ -1,5 +1,8 @@ const dotenv = require("dotenv"); const handler = require("./monthly").handler; -dotenv.config({ path: "../../../../.env" }); +dotenv.config({ + path: + !!process.env.DEV === true ? "../../../../.dev.env" : "../../../../.env", +}); handler(); diff --git a/src/modules/jobs/monthly/monthly.js b/src/modules/jobs/monthly/monthly.js index 177c977..aa11698 100644 --- a/src/modules/jobs/monthly/monthly.js +++ b/src/modules/jobs/monthly/monthly.js @@ -1,6 +1,6 @@ const TABLES = require("../../../constants/tables").TABLES; const services = require("../../../services"); -const { addNewUsers } = require("../../../services/addNewUsers"); +const { updateUsers } = require("../../../services/updateUsers"); const { Client, GatewayIntentBits } = require("discord.js"); exports.handler = async () => { @@ -12,8 +12,10 @@ exports.handler = async () => { await client.login(process.env.BOT_TOKEN); // update users if needed, based on the "chore-boy" role - const users = await addNewUsers(client); - const scores = users.sort((u1, u2) => u2.numCycleChores - u1.numCycleChores); + const activeUsers = (await updateUsers(client)).filter((u) => !u.inactive); + const scores = activeUsers.sort( + (u1, u2) => u2.numCycleChores - u1.numCycleChores + ); if (scores.length > 0) { const lowestScoring = scores[scores.length - 1]; @@ -31,7 +33,7 @@ exports.handler = async () => { await services.db.batchWrite( TABLES.USERS, - users.map((user) => ({ + activeUsers.map((user) => ({ ...user, numCycleChores: 0, })) diff --git a/src/modules/jobs/weekly/debug.js b/src/modules/jobs/weekly/debug.js index a89c5b4..eae7767 100644 --- a/src/modules/jobs/weekly/debug.js +++ b/src/modules/jobs/weekly/debug.js @@ -1,5 +1,8 @@ const dotenv = require("dotenv"); const handler = require("./weekly").handler; -dotenv.config({ path: "../../../../.env" }); +dotenv.config({ + path: + !!process.env.DEV === true ? "../../../../.dev.env" : "../../../../.env", +}); handler(); diff --git a/src/modules/jobs/weekly/weekly.js b/src/modules/jobs/weekly/weekly.js index edc71bc..d6efe4c 100644 --- a/src/modules/jobs/weekly/weekly.js +++ b/src/modules/jobs/weekly/weekly.js @@ -4,7 +4,7 @@ const services = require("../../../services"); const { Client, GatewayIntentBits } = require("discord.js"); const _ = require("lodash"); const dayjs = require("dayjs"); -const { addNewUsers } = require("../../../services/addNewUsers"); +const { updateUsers } = require("../../../services/updateUsers"); const { removeRandomFromList, } = require("../../../helpers/removeRandomFromList"); @@ -16,6 +16,7 @@ exports.handler = async () => { intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers], }); // Log in to Discord with your client's token + console.log("logging into Discord.js with ", process.env.BOT_TOKEN); await client.login(process.env.BOT_TOKEN); // send an initial "all done for the week" message to the channel @@ -38,7 +39,7 @@ exports.handler = async () => { const { displayName, user } = chore; await services.messageChoresChannel( client, - `<@${user.id}> didn't finish their chore this week (${displayName})` + `<@${user}> didn't finish their chore this week (${displayName})` ); }) ); @@ -55,10 +56,10 @@ exports.handler = async () => { } // update users if needed, based on the "chore-boy" role - const users = await addNewUsers(client); + const activeUsers = (await updateUsers(client)).filter((u) => !u.inactive); // duplicate users list to list named reviewers - const reviewers = users; + const reviewers = activeUsers; // make empty list named assignedChores const assignedChores = []; @@ -73,8 +74,10 @@ exports.handler = async () => { unassignedChores = await services.getTodoChores(); } + const usersToWrite = []; + await Promise.all( - users.map(async (user) => { + activeUsers.map(async (user) => { // if the length of the unassigned chores list is 0, move all complete chores to unassigned if (unassignedChores.length === 0) { // TODO: big deal here! celebrate all chores being done! @@ -89,14 +92,15 @@ exports.handler = async () => { if (!selectedChore) { console.warn("unable to select a chore for ", user.displayName); } else { + usersToWrite.push({ + ...user, + currentChore: selectedChore.id, + }); const choreToAssign = { ...selectedChore, status: CHORE_STATES.ASSIGNED, - user: { - ...user, - currentChore: selectedChore.id, - }, - reviewer: _.cloneDeep(reviewer), + user: user.id, + reviewer: reviewer.id, }; // add chore to assignedChores list assignedChores.push(choreToAssign); @@ -106,23 +110,23 @@ exports.handler = async () => { // after loop: iterate over assignedChores (Promise.all) and send message for each to channel @ing user with their new chore, // update user and chore in db + console.log("number of assigned chores: ", assignedChores.length); await services.messageChoresChannel(client, "### New Chores"); await Promise.all( assignedChores.map(async (chore) => { await services.messageChoresChannel( client, - `**<@${chore.user.id}>**\n${getChoreMessage(chore)}` + `**<@${chore.user}>**\n${getChoreMessage(chore)}` ); }) ); // write all the new data to the db await services.db.batchWrite(TABLES.CHORES, assignedChores); - await services.db.batchWrite( - TABLES.USERS, - assignedChores.map((c) => c.user) - ); + await services.db.batchWrite(TABLES.USERS, usersToWrite); // IMPORTANT: destroy the discord.js client, otherwise the application hangs await client.destroy(); + + console.log("done."); }; diff --git a/src/modules/proxy/proxy-function.js b/src/modules/proxy/proxy-function.js index 1112f24..b44aea4 100755 --- a/src/modules/proxy/proxy-function.js +++ b/src/modules/proxy/proxy-function.js @@ -22,6 +22,7 @@ async function handler(event) { ); if (!isVerified) { + console.error("401 return code"); return { statusCode: 401, body: JSON.stringify("invalid request signature"), @@ -40,6 +41,7 @@ async function handler(event) { // Handle command (send to SNS and split to one of Lambdas) if (body.data.name) { + console.log(body.data.name); var eventText = JSON.stringify(body, null, 2); var params = { Message: eventText, @@ -49,9 +51,10 @@ async function handler(event) { command: { DataType: "String", StringValue: body.data.name }, }, }; + console.log("sending ", params); // Create promise and SNS service object const snsClient = new SNSClient(); - snsClient.send(new PublishCommand(params)); + await snsClient.send(new PublishCommand(params)); return { statusCode: 200, diff --git a/src/services/addNewUsers.js b/src/services/addNewUsers.js deleted file mode 100644 index 765394e..0000000 --- a/src/services/addNewUsers.js +++ /dev/null @@ -1,37 +0,0 @@ -const { CHORE_ROLE } = require("../constants/roles"); -const { TABLES } = require("../constants/tables"); -const services = require("../services"); - -exports.addNewUsers = async (client) => { - const newUsers = []; - const guild = client.guilds.resolve(process.env.GUILD_ID); - const members = await guild.members.fetch({ force: true }); - const allRoleUsers = members - .filter((m) => { - return m.roles.cache.find((r) => r.name === CHORE_ROLE); - }) - .map((u) => { - const newUser = { id: u.id, displayName: u.displayName }; - return newUser; - }); - - // get all users - let users = await services.getAllUsers(); - const userIds = users.map((u) => u.id); - - allRoleUsers.filter((u) => { - if (!userIds.includes(u.id)) { - newUsers.push({ - ...u, - numCycleChores: 0, - numAllTimeChores: 0, - }); - } - }); - if (newUsers.length > 0) { - await services.db.batchWrite(TABLES.USERS, newUsers); - users = await services.getAllUsers(); - } - - return users; -}; diff --git a/src/services/dmUser.js b/src/services/dmUser.js index fe1ae6f..717eaa1 100644 --- a/src/services/dmUser.js +++ b/src/services/dmUser.js @@ -1,5 +1,9 @@ exports.dmUser = async (client, userId, message) => { const user = await client.users.fetch(userId); + console.log( + "going to try dming the user... are they a bot though? ", + user.bot ? "yes." : "no." + ); if (!user.bot) { await user.send(message); } diff --git a/src/services/getChores.js b/src/services/getChores.js index 2a23c2c..7dd3f1e 100644 --- a/src/services/getChores.js +++ b/src/services/getChores.js @@ -10,6 +10,12 @@ const _getChoresByState = async (state) => { return allChores.filter((chore) => chore.status === state); }; +const getChore = async (choreId) => { + // get all chores from DynamoDB + const chore = await db.getItem(TABLES.CHORES, choreId); + return chore; +}; + const getAllChores = async () => { // get all chores from DynamoDB const chores = await db.scan(TABLES.CHORES); @@ -34,4 +40,5 @@ module.exports = { getCompletedChores, getIncompleteChores, getTodoChores, + getChore, }; diff --git a/src/services/getUser.js b/src/services/getUser.js new file mode 100644 index 0000000..1b4a9b8 --- /dev/null +++ b/src/services/getUser.js @@ -0,0 +1,11 @@ +const db = require("./db"); +const TABLES = require("../constants/tables").TABLES; + +const getUser = async (userId) => { + // get all users from DynamoDB + return await db.getItem(TABLES.USERS, userId); +}; + +module.exports = { + getUser, +}; diff --git a/src/services/messageChoresChannel.js b/src/services/messageChoresChannel.js index e96340a..d26f06f 100644 --- a/src/services/messageChoresChannel.js +++ b/src/services/messageChoresChannel.js @@ -1,10 +1,6 @@ -let channel = null; - const messageChoresChannel = async (client, message) => { - if (channel === null) { - const CHANNEL_ID = process.env.CHANNEL_ID; - channel = await client.channels.fetch(CHANNEL_ID); - } + const CHANNEL_ID = process.env.CHANNEL_ID; + const channel = await client.channels.fetch(CHANNEL_ID); await channel.send(message); }; diff --git a/src/services/package.json b/src/services/package.json index a0e0a32..a1034b9 100644 --- a/src/services/package.json +++ b/src/services/package.json @@ -8,6 +8,7 @@ "@aws-sdk/client-dynamodb": "^3.529.1", "@aws-sdk/lib-dynamodb": "^3.529.1", "@aws-sdk/util-dynamodb": "^3.529.1", - "discord.js": "^14.14.1" + "discord.js": "^14.14.1", + "lodash": "^4.17.21" } } diff --git a/src/services/updateUsers.js b/src/services/updateUsers.js new file mode 100644 index 0000000..8831292 --- /dev/null +++ b/src/services/updateUsers.js @@ -0,0 +1,50 @@ +const { CHORE_ROLE } = require("../constants/roles"); +const { TABLES } = require("../constants/tables"); +const services = require("."); +const _ = require("lodash"); + +exports.updateUsers = async (client) => { + const guild = client.guilds.resolve(process.env.GUILD_ID); + const members = await guild.members.fetch({ force: true }); + const currentUserList = members + .filter((m) => { + return m.roles.cache.find((r) => r.name === CHORE_ROLE); + }) + .map((u) => { + return { id: u.id, displayName: u.displayName }; + }); + const currentUserIds = currentUserList.map((u) => u.id); + + // get all users + let dbUserList = await services.getAllUsers(); + // new users are ones that are in the current collection but weren't in the DB + const newUsers = _.differenceBy(currentUserList, dbUserList, "id"); + // users that are now inactive are ones that were in the DB but aren't in our current list + const inactiveUsers = _.differenceBy(dbUserList, currentUserList, "id"); + // current users, to keep + const currentUsers = _.intersectionBy(dbUserList, currentUserList, "id"); + + // create list of current users + const users = [ + ...newUsers.map((u) => ({ + ...u, + numCycleChores: 0, + numAllTimeChores: 0, + inactive: false, + })), + ...inactiveUsers.map((u) => ({ + ...u, + inactive: true, + })), + ...currentUsers.map((u) => ({ + ...u, + inactive: currentUserIds.includes(u.id) ? false : true, + })), + ]; + + if (users.length > 0) { + await services.db.batchWrite(TABLES.USERS, users); + } + + return users; +}; diff --git a/yarn.lock b/yarn.lock index f583682..32fd5ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -796,6 +796,11 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.21.3" +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" @@ -966,6 +971,11 @@ callsites@^3.0.0: resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + integrity sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg== + camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -1013,6 +1023,15 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + integrity sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w== + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + cliui@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" @@ -1027,6 +1046,11 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== + 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" @@ -1095,6 +1119,11 @@ debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: dependencies: ms "2.1.2" +decamelize@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + dedent@^1.0.0: version "1.5.1" resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" @@ -1147,7 +1176,7 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -error-ex@^1.3.1: +error-ex@^1.2.0, 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== @@ -1352,6 +1381,14 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA== + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.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" @@ -1412,6 +1449,11 @@ gensync@^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@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + 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" @@ -1434,7 +1476,7 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^7.1.3, glob@^7.1.4: +glob@^7.0.0, glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -1458,7 +1500,7 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" -graceful-fs@^4.2.9: +graceful-fs@^4.1.2, 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== @@ -1485,6 +1527,11 @@ hasown@^2.0.0: dependencies: function-bind "^1.1.2" +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== + html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" @@ -1534,6 +1581,16 @@ inherits@2: resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ== + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -1551,6 +1608,13 @@ is-extglob@^2.1.1: resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== + dependencies: + number-is-nan "^1.0.0" + 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" @@ -1583,6 +1647,11 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" @@ -2066,6 +2135,13 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw== + dependencies: + invert-kv "^1.0.0" + leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -2084,6 +2160,17 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A== + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.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" @@ -2098,6 +2185,11 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +lodash.assign@^4.1.0, lodash.assign@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + integrity sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw== + lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" @@ -2216,6 +2308,16 @@ node-releases@^2.0.14: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +normalize-package-data@^2.3.2: + 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-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" @@ -2228,6 +2330,11 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== + once@^1.3.0: version "1.4.0" resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" @@ -2254,6 +2361,13 @@ optionator@^0.9.3: prelude-ls "^1.2.1" type-check "^0.4.0" +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + integrity sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g== + dependencies: + lcid "^1.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" @@ -2294,6 +2408,13 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ== + dependencies: + error-ex "^1.2.0" + parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -2304,6 +2425,13 @@ parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ== + dependencies: + pinkie-promise "^2.0.0" + path-exists@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" @@ -2329,6 +2457,15 @@ path-to-regexp@^6.2.1: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5" integrity sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw== +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg== + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -2339,6 +2476,23 @@ picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw== + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== + pirates@^4.0.4: version "4.0.6" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" @@ -2393,11 +2547,48 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A== + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ== + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== + dependencies: + resolve "^1.1.6" + +recursive-install@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/recursive-install/-/recursive-install-1.4.0.tgz#f4db1519a1d77f550b11e8553fac809cbaf3e763" + integrity sha512-pK7bU5PUe5UVHxHJseTQaAmSD7qTtIyhNVhM4u6yru9rkicbxLYhPwXsHhPSxwWLyxmEHx8Fba59BhlHWSGwDA== + dependencies: + shelljs "^0.7.0" + yargs "^5.0.0" + 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-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug== + resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -2420,7 +2611,7 @@ resolve.exports@^2.0.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== -resolve@^1.1.7, resolve@^1.20.0: +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.20.0: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -2455,6 +2646,11 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +"semver@2 || 3 || 4 || 5": + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" @@ -2467,6 +2663,11 @@ semver@^7.5.3, semver@^7.5.4: dependencies: lru-cache "^6.0.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== + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" @@ -2479,6 +2680,15 @@ shebang-regex@^3.0.0: resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +shelljs@^0.7.0: + version "0.7.8" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3" + integrity sha512-/YF5Uk8hcwi7ima04ppkbA4RaRMdPMBfwAvAf8sufYOxsJRtbdoBsT8vGvlb+799BrlGdYrd+oczIA2eN2JdWA== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.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" @@ -2519,6 +2729,32 @@ source-map@^0.6.0, source-map@^0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +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.5.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" + integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== + +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.17" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz#887da8aa73218e51a1d917502d79863161a93f9c" + integrity sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg== + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -2539,6 +2775,15 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.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" @@ -2548,6 +2793,13 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== + dependencies: + ansi-regex "^2.0.0" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" @@ -2555,6 +2807,13 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g== + dependencies: + is-utf8 "^0.2.0" + strip-bom@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" @@ -2632,11 +2891,6 @@ tslib@^2.1.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== -tweetnacl@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" @@ -2700,6 +2954,14 @@ v8-to-istanbul@^9.0.1: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^2.0.0" +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" + walker@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" @@ -2707,6 +2969,11 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + integrity sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ== + which@^2.0.1: version "2.0.2" resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" @@ -2714,6 +2981,19 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +window-size@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + integrity sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw== + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw== + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -2736,6 +3016,11 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" +y18n@^3.2.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696" + integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" @@ -2756,6 +3041,14 @@ yargs-parser@^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-parser@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-3.2.0.tgz#5081355d19d9d0c8c5d81ada908cb4e6d186664f" + integrity sha512-eANlJIqYwhwS/asi4ybKxkeJYUIjNMZXL36C/KICV5jyudUZWp+/lEfBHM0PuJcQjBfs00HwqePEQjtLJd+Kyw== + dependencies: + camelcase "^3.0.0" + lodash.assign "^4.1.0" + yargs@^17.3.1: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" @@ -2769,6 +3062,26 @@ yargs@^17.3.1: y18n "^5.0.5" yargs-parser "^21.1.1" +yargs@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-5.0.0.tgz#3355144977d05757dbb86d6e38ec056123b3a66e" + integrity sha512-krgVLGNhMWUVY1EJkM/bgbvn3yCIRrsZp6KaeX8hx8ztT+jBtX7/flTQcSHe5089xIDQRUsEr2mzlZVNe/7P5w== + dependencies: + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + lodash.assign "^4.2.0" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + window-size "^0.2.0" + y18n "^3.2.1" + yargs-parser "^3.2.0" + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"