diff --git a/.babelrc b/.babelrc index 0639bf7..c89ccde 100644 --- a/.babelrc +++ b/.babelrc @@ -1,5 +1,25 @@ { - "presets": [ - "@babel/preset-env" + "presets": [ + "@babel/preset-env" + ], + "plugins": [ + [ + "module-resolver", + { + "root": [ + "." + ], + "alias": { + "^@/(.+)": "./\\1" + } + } ] + ], + "env": { + "test": { + "plugins": [ + "@babel/plugin-transform-runtime" + ] + } + } } \ No newline at end of file diff --git a/.github/workflows/master_ncn-backend-v2-new.yml b/.github/workflows/master_ncn-backend-v2-new.yml new file mode 100644 index 0000000..85f2b4a --- /dev/null +++ b/.github/workflows/master_ncn-backend-v2-new.yml @@ -0,0 +1,62 @@ +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy Node.js app to Azure Web App - ncn-backend-v2-new + +on: + push: + branches: + - master + workflow_dispatch: + +env: + POSTGRES_URL: ${{ secrets.POSTGRES_URL }} + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Set up Node.js version + uses: actions/setup-node@v1 + with: + node-version: '16.x' + + - name: npm install, build, and test + run: yarn + + - name: Generate Prisma Client + run: npx prisma generate + + - name: zip artifact for deployment + run: zip -r rel.zip ./* .babelrc .env.defaults + + - name: Upload artifact for deployment job + uses: actions/upload-artifact@v2 + with: + name: node-app + path: rel.zip + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v2 + with: + name: node-app + + - name: 'Deploy to Azure Web App' + id: deploy-to-webapp + uses: azure/webapps-deploy@v2 + with: + app-name: 'ncn-backend-v2-new' + slot-name: 'Production' + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_D1CB065A6D4A48678ABF45CDA240C02C }} + package: rel.zip diff --git a/.github/workflows/master_ncn-backend-v2.yml b/.github/workflows/master_ncn-backend-v2.yml index 91b4637..3d87500 100644 --- a/.github/workflows/master_ncn-backend-v2.yml +++ b/.github/workflows/master_ncn-backend-v2.yml @@ -28,7 +28,7 @@ jobs: run: yarn - name: Generate Prisma Client - run: npx prisma generate --schema=./src/prisma/schema.prisma + run: npx prisma generate - name: zip artifact for deployment run: zip -r --symlinks rel.zip ./* .babelrc .env.defaults diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..841a3ca --- /dev/null +++ b/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + setupFilesAfterEnv: ["./mocks.js"], +}; diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..59b06ac --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "baseUrl": "./", + "paths": { + "@/*": [ + "./*" + ], + } + }, + "exclude": [ + "node_modules", + "dist" + ] +} diff --git a/mocks.js b/mocks.js new file mode 100644 index 0000000..b8d32ed --- /dev/null +++ b/mocks.js @@ -0,0 +1,3 @@ +jest.mock("./prisma/index"); +jest.mock("./src/auth"); +jest.mock("./src/utils/auth0_client"); diff --git a/package.json b/package.json index d2a6b8c..c0fa719 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@prisma/client": "^4.0.0", "@sendgrid/mail": "^7.6.0", "axios": "^0.27.2", + "babel-plugin-module-resolver": "^4.1.0", "body-parser": "^1.19.0", "cors": "^2.8.5", "dotenv-defaults": "^3.0.0", @@ -32,12 +33,14 @@ "server": "npx nodemon src/server.js --ext js --watch src --exec babel-node", "azure": "babel-node src/server.js", "lint": "./node_modules/.bin/eslint --config=./.eslintrc.json .", - "lint-fix": "./node_modules/.bin/eslint --config=./.eslintrc.json . --cache --fix" + "lint-fix": "./node_modules/.bin/eslint --config=./.eslintrc.json . --cache --fix", + "test": "jest -i \".*.test.js\"" }, "lint-staged": { "*.{js,jsx,ts,tsx}": "eslint --cache --fix" }, "devDependencies": { + "@babel/plugin-transform-runtime": "^7.18.10", "eslint": "^8.0.1", "eslint-config-prettier": "^8.5.0", "eslint-config-standard": "^17.0.0", @@ -46,7 +49,9 @@ "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-promise": "^6.0.0", "husky": "^8.0.1", + "jest": "^28.1.3", "lint-staged": "^13.0.3", - "prettier": "^2.7.1" + "prettier": "^2.7.1", + "supertest": "^6.2.4" } } diff --git a/prisma/__mocks__/index.js b/prisma/__mocks__/index.js new file mode 100644 index 0000000..5ceeda8 --- /dev/null +++ b/prisma/__mocks__/index.js @@ -0,0 +1,43 @@ +import { PrismaClient } from "@prisma/client"; +import { execSync } from "child_process"; +import { URL } from "url"; +import { insertStubData } from "../stubData"; + +const schemaId = `test`; +const url = makePostgresURL(schemaId); +process.env.POSTGRES_URL = url; +const prisma = new PrismaClient({ + datasources: { db: { url } }, +}); + +jest.setTimeout(8 * 1000); + +beforeAll(async () => { + console.log(`Initializing DB...`); + execSync(`npx prisma db push`, { + env: { + ...process.env, + POSTGRES_URL: url, + }, + }); + await insertStubData(); + console.log(`DB initialization finished.`); +}); + +afterAll(async () => { + await prisma.$executeRawUnsafe( + `DROP SCHEMA IF EXISTS "${schemaId}" CASCADE;` + ); + await prisma.$disconnect(); +}); + +function makePostgresURL(schema) { + if (!process.env.POSTGRES_URL) { + throw new Error("Cannot find `POSTGRES_URL` in env variables"); + } + const url = new URL(process.env.POSTGRES_URL); + url.searchParams.set("schema", schema); + return url.toString(); +} + +export default prisma; diff --git a/prisma/index.js b/prisma/index.js new file mode 100644 index 0000000..b5bf6ce --- /dev/null +++ b/prisma/index.js @@ -0,0 +1,5 @@ +import { PrismaClient } from "@prisma/client"; + +const prisma = new PrismaClient(); + +export default prisma; diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..d262930 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,173 @@ +generator client { + provider = "prisma-client-js" + previewFeatures = ["fullTextSearch"] +} + +datasource db { + provider = "postgresql" + url = env("POSTGRES_URL") +} + +model course_areas { + course_id String + area_id String + areas areas @relation(fields: [area_id], references: [id]) + courses courses @relation(fields: [course_id], references: [id], onDelete: Cascade) + + @@id([course_id, area_id]) +} + +model course_departments { + course_id String + department_id String + courses courses @relation(fields: [course_id], references: [id], onDelete: Cascade) + departments departments @relation(fields: [department_id], references: [id]) + + @@id([course_id, department_id]) +} + +model course_prerequisites { + course_id String + pre_course_id String + courses_course_prerequisites_course_idTocourses courses @relation("course_prerequisites_course_idTocourses", fields: [course_id], references: [id], onDelete: Cascade) + courses_course_prerequisites_pre_course_idTocourses courses @relation("course_prerequisites_pre_course_idTocourses", fields: [pre_course_id], references: [id]) + + @@id([course_id, pre_course_id]) +} + +model course_schedules { + course_id String + weekday Int + interval String + location String + courses courses @relation(fields: [course_id], references: [id], onDelete: Cascade) + + @@id([course_id, weekday, interval, location]) +} + +model course_specialties { + course_id String + specialty_id String + courses courses @relation(fields: [course_id], references: [id], onDelete: Cascade) + specialties specialties @relation(fields: [specialty_id], references: [id]) + + @@id([course_id, specialty_id]) +} + +model course_tables { + id String @id + name String + user_id String? + semester String? + courses String[] + expire_ts DateTime? @db.Timestamp(6) + users users? @relation(fields: [user_id], references: [id], onUpdate: Restrict) +} + +model courses { + id String @id + serial String + code String + identifier String + name String + semester String + teacher String? + limitation String? + note String? + cool_url String? + credits Float? + can_be_selective Boolean + is_half_year Boolean + requirement course_requirements + language course_languages + provider course_providers + slot Int + enroll_method Int + intensive_weeks Int[] + departments_raw String[] + class String? + areas course_areas[] + departments course_departments[] + prerequisites course_prerequisites[] @relation("course_prerequisites_course_idTocourses") + prerequisite_of course_prerequisites[] @relation("course_prerequisites_pre_course_idTocourses") + schedules course_schedules[] + specialties course_specialties[] +} + +model users { + id String @id + name String + email String + student_id String? + year Int @default(0) + major String? + d_major String? + minors String[] + languages String[] + favorites String[] + course_tables String[] + history_courses String[] + d_major_dept departments? @relation("departmentsTousers_d_major", fields: [d_major], references: [id], onDelete: Restrict, onUpdate: Restrict) + major_dept departments? @relation("departmentsTousers_major", fields: [major], references: [id], onDelete: Restrict, onUpdate: Restrict) + course_tables_course_tablesTousers course_tables[] + + @@unique([id, email, student_id]) +} + +model areas { + id String @id + code String + name String + course_areas course_areas[] + + @@unique([id, code, name]) +} + +model colleges { + id String @id + name String + departments departments[] + + @@unique([id, name]) +} + +model departments { + id String @id + college_id String? + name_short String? + name_full String + name_alt String? + colleges colleges? @relation(fields: [college_id], references: [id], onDelete: Restrict, onUpdate: Restrict, map: "id") + course_departments course_departments[] + users_departmentsTousers_d_major users[] @relation("departmentsTousers_d_major") + users_departmentsTousers_major users[] @relation("departmentsTousers_major") + + @@unique([id, name_full]) +} + +model specialties { + id String @id + name String + course_specialties course_specialties[] + + @@unique([id, name]) +} + +enum course_languages { + zh_TW @map("zh-TW") + en_US @map("en-US") +} + +enum course_providers { + ntu + ntnu + ntust + other +} + +enum course_requirements { + preassign + required + elective + other +} diff --git a/prisma/stubData/areas.json b/prisma/stubData/areas.json new file mode 100644 index 0000000..85a571b --- /dev/null +++ b/prisma/stubData/areas.json @@ -0,0 +1,67 @@ +[ + { + "id": "chinese", + "code": "共", + "name": "國文領域" + }, + { + "id": "g_a1", + "code": "A1", + "name": "文學與藝術領域" + }, + { + "id": "g_a4", + "code": "A4", + "name": "哲學與道德思考領域" + }, + { + "id": "g_a2", + "code": "A2", + "name": "歷史思維領域" + }, + { + "id": "g_a5", + "code": "A5", + "name": "公民意識與社會分析領域" + }, + { + "id": "shared_selective", + "code": "共", + "name": "共同選修課程" + }, + { + "id": "g_ax", + "code": "AX", + "name": "不分領域通識課程" + }, + { + "id": "g_a3", + "code": "A3", + "name": "世界文明領域" + }, + { + "id": "basic", + "code": "基", + "name": "基本能力課程" + }, + { + "id": "pe_2", + "code": "體", + "name": "專項運動學群" + }, + { + "id": "g_a8", + "code": "A8", + "name": "生命科學領域" + }, + { + "id": "millitary", + "code": "軍", + "name": "軍訓課程" + }, + { + "id": "g_a7", + "code": "A7", + "name": "物質科學領域" + } +] \ No newline at end of file diff --git a/prisma/stubData/colleges.json b/prisma/stubData/colleges.json new file mode 100644 index 0000000..dec33a8 --- /dev/null +++ b/prisma/stubData/colleges.json @@ -0,0 +1,22 @@ +[ + { + "id": "6", + "name": "生物資源暨農學院" + }, + { + "id": "1", + "name": "文學院" + }, + { + "id": "3", + "name": "社會科學院" + }, + { + "id": "5", + "name": "工學院" + }, + { + "id": "2", + "name": "理學院" + } +] \ No newline at end of file diff --git a/prisma/stubData/course_areas.json b/prisma/stubData/course_areas.json new file mode 100644 index 0000000..ac92065 --- /dev/null +++ b/prisma/stubData/course_areas.json @@ -0,0 +1,190 @@ +[ + { + "course_id": "1102_97016", + "area_id": "pe_2" + }, + { + "course_id": "1102_97004", + "area_id": "pe_2" + }, + { + "course_id": "1102_97109", + "area_id": "pe_2" + }, + { + "course_id": "1102_97135", + "area_id": "pe_2" + }, + { + "course_id": "1102_97153", + "area_id": "pe_2" + }, + { + "course_id": "1102_62726", + "area_id": "g_a2" + }, + { + "course_id": "1102_62726", + "area_id": "g_ax" + }, + { + "course_id": "1102_01013", + "area_id": "chinese" + }, + { + "course_id": "1102_82924", + "area_id": "g_a5" + }, + { + "course_id": "1102_28094", + "area_id": "g_ax" + }, + { + "course_id": "1102_49953", + "area_id": "g_ax" + }, + { + "course_id": "1102_31464", + "area_id": "g_ax" + }, + { + "course_id": "1102_82924", + "area_id": "g_ax" + }, + { + "course_id": "1102_74433", + "area_id": "g_a7" + }, + { + "course_id": "1102_13785", + "area_id": "g_a2" + }, + { + "course_id": "1102_74566", + "area_id": "g_ax" + }, + { + "course_id": "1102_74433", + "area_id": "g_ax" + }, + { + "course_id": "1102_49014", + "area_id": "g_ax" + }, + { + "course_id": "1102_72915", + "area_id": "g_ax" + }, + { + "course_id": "1102_40793", + "area_id": "g_ax" + }, + { + "course_id": "1102_13785", + "area_id": "g_ax" + }, + { + "course_id": "1102_49953", + "area_id": "g_a7" + }, + { + "course_id": "1102_72915", + "area_id": "g_a2" + }, + { + "course_id": "1102_16800", + "area_id": "basic" + }, + { + "course_id": "1102_69175", + "area_id": "g_ax" + }, + { + "course_id": "1102_01016", + "area_id": "chinese" + }, + { + "course_id": "1102_74566", + "area_id": "g_a7" + }, + { + "course_id": "1102_82924", + "area_id": "g_a8" + }, + { + "course_id": "1102_37963", + "area_id": "g_ax" + }, + { + "course_id": "1102_85970", + "area_id": "g_ax" + }, + { + "course_id": "1102_93005", + "area_id": "millitary" + }, + { + "course_id": "1102_31464", + "area_id": "g_a1" + }, + { + "course_id": "1102_28094", + "area_id": "g_a1" + }, + { + "course_id": "1102_74566", + "area_id": "g_a8" + }, + { + "course_id": "1102_62321", + "area_id": "g_ax" + }, + { + "course_id": "1102_62321", + "area_id": "g_a8" + }, + { + "course_id": "1102_37963", + "area_id": "g_a1" + }, + { + "course_id": "1102_49014", + "area_id": "basic" + }, + { + "course_id": "1102_01052", + "area_id": "chinese" + }, + { + "course_id": "1102_62726", + "area_id": "g_a3" + }, + { + "course_id": "1102_35992", + "area_id": "shared_selective" + }, + { + "course_id": "1102_16800", + "area_id": "g_ax" + }, + { + "course_id": "1102_85970", + "area_id": "basic" + }, + { + "course_id": "1102_93010", + "area_id": "millitary" + }, + { + "course_id": "1102_69175", + "area_id": "g_a1" + }, + { + "course_id": "1102_40793", + "area_id": "g_a1" + }, + { + "course_id": "1102_74433", + "area_id": "g_a4" + } +] \ No newline at end of file diff --git a/prisma/stubData/course_departments.json b/prisma/stubData/course_departments.json new file mode 100644 index 0000000..b390302 --- /dev/null +++ b/prisma/stubData/course_departments.json @@ -0,0 +1,122 @@ +[ + { + "course_id": "1102_41354", + "department_id": "1070" + }, + { + "course_id": "1102_20169", + "department_id": "3050" + }, + { + "course_id": "1102_21495", + "department_id": "1070" + }, + { + "course_id": "1102_32509", + "department_id": "3030" + }, + { + "course_id": "1102_69175", + "department_id": "1010" + }, + { + "course_id": "1102_16245", + "department_id": "1070" + }, + { + "course_id": "1102_77199", + "department_id": "3030" + }, + { + "course_id": "1102_55891", + "department_id": "3030" + }, + { + "course_id": "1102_47796", + "department_id": "3030" + }, + { + "course_id": "1102_43793", + "department_id": "3030" + }, + { + "course_id": "1102_53902", + "department_id": "1070" + }, + { + "course_id": "1102_68363", + "department_id": "2070" + }, + { + "course_id": "1102_40793", + "department_id": "1020" + }, + { + "course_id": "1102_62127", + "department_id": "1070" + }, + { + "course_id": "1102_52721", + "department_id": "3030" + }, + { + "course_id": "1102_95129", + "department_id": "3030" + }, + { + "course_id": "1102_89734", + "department_id": "1070" + }, + { + "course_id": "1102_17788", + "department_id": "1070" + }, + { + "course_id": "1102_76148", + "department_id": "1070" + }, + { + "course_id": "1102_29882", + "department_id": "3030" + }, + { + "course_id": "1102_42441", + "department_id": "3030" + }, + { + "course_id": "1102_67104", + "department_id": "3030" + }, + { + "course_id": "1102_10388", + "department_id": "5020" + }, + { + "course_id": "1102_44138", + "department_id": "1070" + }, + { + "course_id": "1102_71631", + "department_id": "2010" + }, + { + "course_id": "1102_27006", + "department_id": "1070" + }, + { + "course_id": "1102_70670", + "department_id": "5050" + }, + { + "course_id": "1102_74433", + "department_id": "6050" + }, + { + "course_id": "1102_85244", + "department_id": "3030" + }, + { + "course_id": "1102_76808", + "department_id": "3030" + } +] \ No newline at end of file diff --git a/prisma/stubData/course_schedules.json b/prisma/stubData/course_schedules.json new file mode 100644 index 0000000..e831173 --- /dev/null +++ b/prisma/stubData/course_schedules.json @@ -0,0 +1,890 @@ +[ + { + "course_id": "1102_01013", + "weekday": 4, + "interval": "7", + "location": "普306" + }, + { + "course_id": "1102_01013", + "weekday": 4, + "interval": "8", + "location": "普306" + }, + { + "course_id": "1102_01013", + "weekday": 4, + "interval": "9", + "location": "普306" + }, + { + "course_id": "1102_01016", + "weekday": 4, + "interval": "7", + "location": "綜402" + }, + { + "course_id": "1102_01016", + "weekday": 4, + "interval": "8", + "location": "綜402" + }, + { + "course_id": "1102_01016", + "weekday": 4, + "interval": "9", + "location": "綜402" + }, + { + "course_id": "1102_01052", + "weekday": 4, + "interval": "7", + "location": "共404" + }, + { + "course_id": "1102_01052", + "weekday": 4, + "interval": "8", + "location": "共404" + }, + { + "course_id": "1102_01052", + "weekday": 4, + "interval": "9", + "location": "共404" + }, + { + "course_id": "1102_10388", + "weekday": 5, + "interval": "3", + "location": "工綜209" + }, + { + "course_id": "1102_10388", + "weekday": 5, + "interval": "4", + "location": "工綜209" + }, + { + "course_id": "1102_10388", + "weekday": 5, + "interval": "5", + "location": "工綜209" + }, + { + "course_id": "1102_13785", + "weekday": 3, + "interval": "7", + "location": "普405" + }, + { + "course_id": "1102_13785", + "weekday": 3, + "interval": "8", + "location": "普405" + }, + { + "course_id": "1102_13785", + "weekday": 3, + "interval": "9", + "location": "普405" + }, + { + "course_id": "1102_16245", + "weekday": 3, + "interval": "3", + "location": "普202" + }, + { + "course_id": "1102_16245", + "weekday": 3, + "interval": "4", + "location": "普202" + }, + { + "course_id": "1102_16800", + "weekday": 3, + "interval": "2", + "location": "共103" + }, + { + "course_id": "1102_16800", + "weekday": 3, + "interval": "3", + "location": "共103" + }, + { + "course_id": "1102_16800", + "weekday": 3, + "interval": "4", + "location": "共103" + }, + { + "course_id": "1102_17788", + "weekday": 1, + "interval": "3", + "location": "普304" + }, + { + "course_id": "1102_17788", + "weekday": 1, + "interval": "4", + "location": "普304" + }, + { + "course_id": "1102_17788", + "weekday": 3, + "interval": "8", + "location": "普301" + }, + { + "course_id": "1102_17788", + "weekday": 3, + "interval": "9", + "location": "普301" + }, + { + "course_id": "1102_20169", + "weekday": 1, + "interval": "6", + "location": "社103" + }, + { + "course_id": "1102_20169", + "weekday": 1, + "interval": "7", + "location": "社103" + }, + { + "course_id": "1102_20169", + "weekday": 1, + "interval": "8", + "location": "社103" + }, + { + "course_id": "1102_21495", + "weekday": 5, + "interval": "3", + "location": "普201" + }, + { + "course_id": "1102_21495", + "weekday": 5, + "interval": "4", + "location": "普201" + }, + { + "course_id": "1102_27006", + "weekday": 1, + "interval": "8", + "location": "普505" + }, + { + "course_id": "1102_27006", + "weekday": 1, + "interval": "9", + "location": "普505" + }, + { + "course_id": "1102_28094", + "weekday": 4, + "interval": "6", + "location": "綜401" + }, + { + "course_id": "1102_28094", + "weekday": 4, + "interval": "7", + "location": "綜401" + }, + { + "course_id": "1102_28094", + "weekday": 4, + "interval": "8", + "location": "綜401" + }, + { + "course_id": "1102_29882", + "weekday": 2, + "interval": "6", + "location": "社科102" + }, + { + "course_id": "1102_29882", + "weekday": 2, + "interval": "7", + "location": "社科102" + }, + { + "course_id": "1102_29882", + "weekday": 3, + "interval": "2", + "location": "社科102" + }, + { + "course_id": "1102_29882", + "weekday": 3, + "interval": "3", + "location": "社科102" + }, + { + "course_id": "1102_29882", + "weekday": 3, + "interval": "4", + "location": "社科102" + }, + { + "course_id": "1102_31464", + "weekday": 5, + "interval": "8", + "location": "博雅202" + }, + { + "course_id": "1102_31464", + "weekday": 5, + "interval": "9", + "location": "博雅202" + }, + { + "course_id": "1102_32509", + "weekday": 1, + "interval": "3", + "location": "社科303" + }, + { + "course_id": "1102_32509", + "weekday": 1, + "interval": "4", + "location": "社科303" + }, + { + "course_id": "1102_32509", + "weekday": 2, + "interval": "3", + "location": "社科303" + }, + { + "course_id": "1102_32509", + "weekday": 2, + "interval": "4", + "location": "社科303" + }, + { + "course_id": "1102_32509", + "weekday": 2, + "interval": "5", + "location": "社科303" + }, + { + "course_id": "1102_35992", + "weekday": 3, + "interval": "2", + "location": "卓R505" + }, + { + "course_id": "1102_35992", + "weekday": 3, + "interval": "3", + "location": "卓R505" + }, + { + "course_id": "1102_35992", + "weekday": 3, + "interval": "4", + "location": "卓R505" + }, + { + "course_id": "1102_37963", + "weekday": 4, + "interval": "8", + "location": "外教劇場" + }, + { + "course_id": "1102_37963", + "weekday": 4, + "interval": "9", + "location": "外教劇場" + }, + { + "course_id": "1102_38601", + "weekday": 4, + "interval": "6", + "location": "綜403" + }, + { + "course_id": "1102_38601", + "weekday": 4, + "interval": "7", + "location": "綜403" + }, + { + "course_id": "1102_38601", + "weekday": 4, + "interval": "8", + "location": "綜403" + }, + { + "course_id": "1102_40793", + "weekday": 1, + "interval": "10", + "location": "博雅102" + }, + { + "course_id": "1102_40793", + "weekday": 3, + "interval": "5", + "location": "博雅102" + }, + { + "course_id": "1102_40793", + "weekday": 3, + "interval": "6", + "location": "博雅102" + }, + { + "course_id": "1102_41354", + "weekday": 5, + "interval": "6", + "location": "普303" + }, + { + "course_id": "1102_41354", + "weekday": 5, + "interval": "7", + "location": "普303" + }, + { + "course_id": "1102_42441", + "weekday": 3, + "interval": "6", + "location": "社科402" + }, + { + "course_id": "1102_42441", + "weekday": 3, + "interval": "7", + "location": "社科402" + }, + { + "course_id": "1102_42441", + "weekday": 3, + "interval": "8", + "location": "社科402" + }, + { + "course_id": "1102_43793", + "weekday": 2, + "interval": "6", + "location": "社科501" + }, + { + "course_id": "1102_43793", + "weekday": 2, + "interval": "7", + "location": "社科501" + }, + { + "course_id": "1102_43793", + "weekday": 3, + "interval": "2", + "location": "社科502" + }, + { + "course_id": "1102_43793", + "weekday": 3, + "interval": "3", + "location": "社科502" + }, + { + "course_id": "1102_43793", + "weekday": 3, + "interval": "4", + "location": "社科502" + }, + { + "course_id": "1102_44138", + "weekday": 2, + "interval": "3", + "location": "普501" + }, + { + "course_id": "1102_44138", + "weekday": 2, + "interval": "4", + "location": "普501" + }, + { + "course_id": "1102_44138", + "weekday": 2, + "interval": "5", + "location": "普501" + }, + { + "course_id": "1102_47796", + "weekday": 5, + "interval": "6", + "location": "社科507" + }, + { + "course_id": "1102_47796", + "weekday": 5, + "interval": "7", + "location": "社科507" + }, + { + "course_id": "1102_47796", + "weekday": 5, + "interval": "8", + "location": "社科507" + }, + { + "course_id": "1102_49014", + "weekday": 2, + "interval": "A", + "location": "卓R505" + }, + { + "course_id": "1102_49014", + "weekday": 2, + "interval": "B", + "location": "卓R505" + }, + { + "course_id": "1102_49014", + "weekday": 2, + "interval": "C", + "location": "卓R505" + }, + { + "course_id": "1102_49953", + "weekday": 4, + "interval": "8", + "location": "大氣B105" + }, + { + "course_id": "1102_49953", + "weekday": 4, + "interval": "9", + "location": "大氣B105" + }, + { + "course_id": "1102_52721", + "weekday": 2, + "interval": "2", + "location": "社科403" + }, + { + "course_id": "1102_52721", + "weekday": 2, + "interval": "3", + "location": "社科403" + }, + { + "course_id": "1102_52721", + "weekday": 2, + "interval": "4", + "location": "社科403" + }, + { + "course_id": "1102_53902", + "weekday": 1, + "interval": "6", + "location": "普204" + }, + { + "course_id": "1102_53902", + "weekday": 1, + "interval": "7", + "location": "普204" + }, + { + "course_id": "1102_55891", + "weekday": 4, + "interval": "2", + "location": "社科405" + }, + { + "course_id": "1102_55891", + "weekday": 4, + "interval": "3", + "location": "社科405" + }, + { + "course_id": "1102_55891", + "weekday": 4, + "interval": "4", + "location": "社科405" + }, + { + "course_id": "1102_62127", + "weekday": 4, + "interval": "3", + "location": "共307" + }, + { + "course_id": "1102_62127", + "weekday": 4, + "interval": "4", + "location": "共307" + }, + { + "course_id": "1102_62321", + "weekday": 2, + "interval": "6", + "location": "普101" + }, + { + "course_id": "1102_62321", + "weekday": 2, + "interval": "7", + "location": "普101" + }, + { + "course_id": "1102_62726", + "weekday": 4, + "interval": "1", + "location": "博雅202" + }, + { + "course_id": "1102_62726", + "weekday": 4, + "interval": "2", + "location": "博雅202" + }, + { + "course_id": "1102_67104", + "weekday": 4, + "interval": "3", + "location": "社科202" + }, + { + "course_id": "1102_67104", + "weekday": 4, + "interval": "4", + "location": "社科202" + }, + { + "course_id": "1102_67104", + "weekday": 5, + "interval": "6", + "location": "社科202" + }, + { + "course_id": "1102_67104", + "weekday": 5, + "interval": "7", + "location": "社科202" + }, + { + "course_id": "1102_67104", + "weekday": 5, + "interval": "8", + "location": "社科202" + }, + { + "course_id": "1102_68363", + "weekday": 2, + "interval": "10", + "location": "南館地下A" + }, + { + "course_id": "1102_68363", + "weekday": 2, + "interval": "7", + "location": "南館地下A" + }, + { + "course_id": "1102_68363", + "weekday": 2, + "interval": "8", + "location": "南館地下A" + }, + { + "course_id": "1102_68363", + "weekday": 2, + "interval": "9", + "location": "南館地下A" + }, + { + "course_id": "1102_69175", + "weekday": 4, + "interval": "6", + "location": "外教劇場" + }, + { + "course_id": "1102_69175", + "weekday": 4, + "interval": "7", + "location": "外教劇場" + }, + { + "course_id": "1102_70670", + "weekday": 2, + "interval": "A", + "location": "工科視聽室" + }, + { + "course_id": "1102_70670", + "weekday": 2, + "interval": "B", + "location": "工科視聽室" + }, + { + "course_id": "1102_70670", + "weekday": 2, + "interval": "C", + "location": "工科視聽室" + }, + { + "course_id": "1102_71631", + "weekday": 2, + "interval": "8", + "location": "新102" + }, + { + "course_id": "1102_71631", + "weekday": 2, + "interval": "9", + "location": "新102" + }, + { + "course_id": "1102_71631", + "weekday": 5, + "interval": "1", + "location": "新102" + }, + { + "course_id": "1102_71631", + "weekday": 5, + "interval": "2", + "location": "新102" + }, + { + "course_id": "1102_72915", + "weekday": 1, + "interval": "8", + "location": "普501" + }, + { + "course_id": "1102_72915", + "weekday": 1, + "interval": "9", + "location": "普501" + }, + { + "course_id": "1102_74433", + "weekday": 3, + "interval": "6", + "location": "博雅101" + }, + { + "course_id": "1102_74433", + "weekday": 3, + "interval": "7", + "location": "博雅101" + }, + { + "course_id": "1102_74566", + "weekday": 1, + "interval": "8", + "location": "普101" + }, + { + "course_id": "1102_74566", + "weekday": 1, + "interval": "9", + "location": "普101" + }, + { + "course_id": "1102_76148", + "weekday": 3, + "interval": "1", + "location": "普204" + }, + { + "course_id": "1102_76148", + "weekday": 3, + "interval": "2", + "location": "普204" + }, + { + "course_id": "1102_76808", + "weekday": 1, + "interval": "2", + "location": "社科403" + }, + { + "course_id": "1102_76808", + "weekday": 1, + "interval": "3", + "location": "社科403" + }, + { + "course_id": "1102_76808", + "weekday": 1, + "interval": "4", + "location": "社科403" + }, + { + "course_id": "1102_77199", + "weekday": 4, + "interval": "2", + "location": "社科502" + }, + { + "course_id": "1102_77199", + "weekday": 4, + "interval": "3", + "location": "社科502" + }, + { + "course_id": "1102_77199", + "weekday": 4, + "interval": "4", + "location": "社科502" + }, + { + "course_id": "1102_82924", + "weekday": 1, + "interval": "8", + "location": "普102" + }, + { + "course_id": "1102_82924", + "weekday": 1, + "interval": "9", + "location": "普102" + }, + { + "course_id": "1102_85244", + "weekday": 4, + "interval": "8", + "location": "社科303" + }, + { + "course_id": "1102_85244", + "weekday": 4, + "interval": "9", + "location": "社科303" + }, + { + "course_id": "1102_85970", + "weekday": 3, + "interval": "10", + "location": "卓R505" + }, + { + "course_id": "1102_85970", + "weekday": 3, + "interval": "7", + "location": "卓R505" + }, + { + "course_id": "1102_85970", + "weekday": 3, + "interval": "8", + "location": "卓R505" + }, + { + "course_id": "1102_85970", + "weekday": 3, + "interval": "9", + "location": "卓R505" + }, + { + "course_id": "1102_93005", + "weekday": 3, + "interval": "6", + "location": "普103" + }, + { + "course_id": "1102_93005", + "weekday": 3, + "interval": "7", + "location": "普103" + }, + { + "course_id": "1102_93010", + "weekday": 2, + "interval": "6", + "location": "新103" + }, + { + "course_id": "1102_93010", + "weekday": 2, + "interval": "7", + "location": "新103" + }, + { + "course_id": "1102_96134", + "weekday": 3, + "interval": "10", + "location": "TR-213" + }, + { + "course_id": "1102_96134", + "weekday": 3, + "interval": "9", + "location": "TR-213" + }, + { + "course_id": "1102_97004", + "weekday": 4, + "interval": "8", + "location": "綜館舞蹈室" + }, + { + "course_id": "1102_97004", + "weekday": 4, + "interval": "9", + "location": "綜館舞蹈室" + }, + { + "course_id": "1102_97016", + "weekday": 1, + "interval": "8", + "location": "綜館技擊AB" + }, + { + "course_id": "1102_97016", + "weekday": 1, + "interval": "9", + "location": "綜館技擊AB" + }, + { + "course_id": "1102_97109", + "weekday": 1, + "interval": "8", + "location": "[醫]館1F" + }, + { + "course_id": "1102_97109", + "weekday": 1, + "interval": "9", + "location": "[醫]館1F" + }, + { + "course_id": "1102_97135", + "weekday": 2, + "interval": "8", + "location": "請洽系所辦" + }, + { + "course_id": "1102_97135", + "weekday": 2, + "interval": "9", + "location": "請洽系所辦" + }, + { + "course_id": "1102_97153", + "weekday": 4, + "interval": "6", + "location": "舊館羽球場" + }, + { + "course_id": "1102_97153", + "weekday": 4, + "interval": "7", + "location": "舊館羽球場" + } +] \ No newline at end of file diff --git a/prisma/stubData/course_tables.json b/prisma/stubData/course_tables.json new file mode 100644 index 0000000..7d4db88 --- /dev/null +++ b/prisma/stubData/course_tables.json @@ -0,0 +1,148 @@ +[ + { + "id": "6a8db590-cb97-4364-a097-e5a9243a13e1", + "name": "三下", + "user_id": "test-user-id-4", + "semester": "1102", + "courses": [ + "1102_17788", + "1102_89734", + "1102_62127", + "1102_41354", + "1102_21495", + "1102_16245", + "1102_76148", + "1102_44138", + "1102_53902", + "1102_74566", + "1102_31464", + "1102_01013", + "1102_37963", + "1102_62726", + "1102_27006", + "1102_62321", + "1102_01052", + "1102_72915", + "1102_49953", + "1102_97109", + "1102_69175", + "1102_28094", + "1102_01016", + "1102_97135", + "1102_97153", + "1102_82924", + "1102_93010", + "1102_93005", + "1102_40793", + "1102_74433" + ], + "expire_ts": null + }, + { + "id": "e9f5c3ad-e5e5-44ee-950e-cd478a6edeba", + "name": "我的課表", + "user_id": "test-user-id-3", + "semester": "1102", + "courses": [ + "1102_52721", + "1102_71631" + ], + "expire_ts": null + }, + { + "id": "8b0d0754-b015-4938-8dc5-1347d83289b1", + "name": "我的課表", + "user_id": "test-user-id-7", + "semester": "1102", + "courses": [ + "1102_67104", + "1102_32509", + "1102_29882", + "1102_43793", + "1102_77199", + "1102_47796", + "1102_55891", + "1102_42441", + "1102_49014", + "1102_35992", + "1102_85970", + "1102_16800", + "1102_38601", + "1102_68363", + "1102_95129", + "1102_76808", + "1102_85244" + ], + "expire_ts": null + }, + { + "id": "dec39a3b-3c33-4ea8-a851-8629ec86b11e", + "name": "我的課表", + "user_id": "test-user-id-8", + "semester": "1102", + "courses": [], + "expire_ts": null + }, + { + "id": "816f8963-93d6-47ad-b03f-c5205c22b61a", + "name": "我的課表", + "user_id": "test-user-id-0", + "semester": "1102", + "courses": [], + "expire_ts": null + }, + { + "id": "4ad5eba9-f328-49b9-aced-ec48e42a1344", + "name": "我的課表", + "user_id": "test-user-id-2", + "semester": "1102", + "courses": [], + "expire_ts": null + }, + { + "id": "a17d4817-14f0-4bb4-b324-b675218ed5ed", + "name": "我的課表", + "user_id": "test-user-id-6", + "semester": "1102", + "courses": [], + "expire_ts": null + }, + { + "id": "e4d48a63-93d4-459d-b7ed-997cde2c6d4a", + "name": "我的課表", + "user_id": "test-user-id-5", + "semester": "1102", + "courses": [ + "1102_20169" + ], + "expire_ts": null + }, + { + "id": "003aebe0-52ef-4067-9340-8c9b0e01d3f7", + "name": "我的課表", + "user_id": null, + "semester": "1102", + "courses": [], + "expire_ts": "2022-01-18T08:36:46.000Z" + }, + { + "id": "005c2aa2-29a7-458e-89b0-276d62fab0a4", + "name": "我的課表", + "user_id": null, + "semester": "1102", + "courses": [ + "1102_97004", + "1102_97016", + "1102_96134" + ], + "expire_ts": "2022-01-21T06:31:03.000Z" + }, + { + "id": "00d7ea13-163c-4f41-bd55-fd2183c8addd", + "name": "我的課表", + "user_id": null, + "semester": "1102", + "courses": [], + "expire_ts": "2022-01-19T16:12:35.000Z" + } +] \ No newline at end of file diff --git a/prisma/stubData/courses.json b/prisma/stubData/courses.json new file mode 100644 index 0000000..251a2b7 --- /dev/null +++ b/prisma/stubData/courses.json @@ -0,0 +1,1439 @@ +[ + { + "id": "1102_97004", + "serial": "97004", + "code": "PE2003", + "identifier": "00250020", + "name": "測試課程 0", + "semester": "1102", + "teacher": "測試教師 0", + "limitation": null, + "note": "note 0", + "cool_url": "", + "credits": 1, + "can_be_selective": false, + "is_half_year": true, + "requirement": "required", + "language": "zh_TW", + "provider": "ntu", + "slot": 40, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "" + ], + "class": "I9" + }, + { + "id": "1102_97016", + "serial": "97016", + "code": "PE2036", + "identifier": "00250390", + "name": "測試課程 1", + "semester": "1102", + "teacher": "測試教師 0", + "limitation": null, + "note": "note 1", + "cool_url": "", + "credits": 1, + "can_be_selective": false, + "is_half_year": true, + "requirement": "required", + "language": "zh_TW", + "provider": "ntu", + "slot": 50, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "" + ], + "class": "26" + }, + { + "id": "1102_01013", + "serial": "01013", + "code": "CHIN8013", + "identifier": "10180210", + "name": "測試課程 2", + "semester": "1102", + "teacher": "測試教師 0", + "limitation": null, + "note": "note 2", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "required", + "language": "zh_TW", + "provider": "ntu", + "slot": 27, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "" + ], + "class": "21" + }, + { + "id": "1102_97135", + "serial": "97135", + "code": "PE2111", + "identifier": "00251360", + "name": "測試課程 3", + "semester": "1102", + "teacher": "測試教師 0", + "limitation": null, + "note": "note 3", + "cool_url": "", + "credits": 1, + "can_be_selective": false, + "is_half_year": true, + "requirement": "required", + "language": "zh_TW", + "provider": "ntu", + "slot": 36, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "" + ], + "class": "97" + }, + { + "id": "1102_97109", + "serial": "97109", + "code": "PE2088", + "identifier": "00251060", + "name": "測試課程 4", + "semester": "1102", + "teacher": "測試教師 0", + "limitation": null, + "note": "note 4", + "cool_url": "", + "credits": 1, + "can_be_selective": false, + "is_half_year": true, + "requirement": "required", + "language": "zh_TW", + "provider": "ntu", + "slot": 36, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "" + ], + "class": "51" + }, + { + "id": "1102_97153", + "serial": "97153", + "code": "PE2142", + "identifier": "00251730", + "name": "測試課程 5", + "semester": "1102", + "teacher": "測試教師 0", + "limitation": null, + "note": "note 5", + "cool_url": null, + "credits": 1, + "can_be_selective": false, + "is_half_year": true, + "requirement": "required", + "language": "zh_TW", + "provider": "ntu", + "slot": 44, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "" + ], + "class": "63" + }, + { + "id": "1102_01052", + "serial": "01052", + "code": "CHIN8017", + "identifier": "10180230", + "name": "測試課程 6", + "semester": "1102", + "teacher": "測試教師 0", + "limitation": null, + "note": "note 6", + "cool_url": null, + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "required", + "language": "zh_TW", + "provider": "ntu", + "slot": 18, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "" + ], + "class": "14" + }, + { + "id": "1102_93005", + "serial": "93005", + "code": "MilTr1008", + "identifier": "00310210", + "name": "測試課程 7", + "semester": "1102", + "teacher": "測試教師 0", + "limitation": null, + "note": "note 7", + "cool_url": "", + "credits": 0, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 300, + "enroll_method": 3, + "intensive_weeks": [], + "departments_raw": [ + "" + ], + "class": "01" + }, + { + "id": "1102_93010", + "serial": "93010", + "code": "MilTr1010", + "identifier": "00310230", + "name": "測試課程 8", + "semester": "1102", + "teacher": "測試教師 1", + "limitation": null, + "note": "note 8", + "cool_url": "", + "credits": 0, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 108, + "enroll_method": 3, + "intensive_weeks": [], + "departments_raw": [ + "" + ], + "class": "02" + }, + { + "id": "1102_69175", + "serial": "69175", + "code": "CHIN1050", + "identifier": "10128320", + "name": "測試課程 9", + "semester": "1102", + "teacher": "測試教師 1", + "limitation": null, + "note": "note 9", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 180, + "enroll_method": 3, + "intensive_weeks": [], + "departments_raw": [ + "中文系", + "" + ], + "class": "02" + }, + { + "id": "1102_01016", + "serial": "01016", + "code": "CHIN8013", + "identifier": "10180210", + "name": "測試課程 10", + "semester": "1102", + "teacher": "測試教師 1", + "limitation": null, + "note": "note 10", + "cool_url": null, + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "required", + "language": "zh_TW", + "provider": "ntu", + "slot": 27, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "" + ], + "class": "24" + }, + { + "id": "1102_40793", + "serial": "40793", + "code": "FL3281", + "identifier": "10237710", + "name": "測試課程 11", + "semester": "1102", + "teacher": "測試教師 1", + "limitation": null, + "note": "note 11", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 150, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "", + "經典人文學程", + "外文系", + "歐洲暨歐盟學" + ], + "class": null + }, + { + "id": "1102_89734", + "serial": "89734", + "code": "JpnL1048", + "identifier": "107001B0", + "name": "測試課程 12", + "semester": "1102", + "teacher": "測試教師 1", + "limitation": null, + "note": "note 12", + "cool_url": "", + "credits": 0, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 15, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "日文系" + ], + "class": "02" + }, + { + "id": "1102_27006", + "serial": "27006", + "code": "JpnL2019", + "identifier": "10720800", + "name": "測試課程 13", + "semester": "1102", + "teacher": "測試教師 1", + "limitation": null, + "note": "note 13", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 50, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "日文系" + ], + "class": null + }, + { + "id": "1102_53902", + "serial": "53902", + "code": "JpnL3010", + "identifier": "10730422", + "name": "測試課程 14", + "semester": "1102", + "teacher": "測試教師 1", + "limitation": null, + "note": "note 14", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "preassign", + "language": "zh_TW", + "provider": "ntu", + "slot": 40, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "日文系" + ], + "class": "01" + }, + { + "id": "1102_21495", + "serial": "21495", + "code": "JpnL3008", + "identifier": "10730302", + "name": "測試課程 15", + "semester": "1102", + "teacher": "測試教師 2", + "limitation": null, + "note": "note 15", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "preassign", + "language": "zh_TW", + "provider": "ntu", + "slot": 70, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "日文系" + ], + "class": null + }, + { + "id": "1102_17788", + "serial": "17788", + "code": "JpnL1008", + "identifier": "10710112", + "name": "測試課程 16", + "semester": "1102", + "teacher": "測試教師 2", + "limitation": null, + "note": "note 16", + "cool_url": "", + "credits": 4, + "can_be_selective": false, + "is_half_year": true, + "requirement": "preassign", + "language": "zh_TW", + "provider": "ntu", + "slot": 70, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "日文系" + ], + "class": null + }, + { + "id": "1102_41354", + "serial": "41354", + "code": "JpnL3016", + "identifier": "10730602", + "name": "測試課程 17", + "semester": "1102", + "teacher": "測試教師 2", + "limitation": null, + "note": "note 17", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 50, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "日文系" + ], + "class": null + }, + { + "id": "1102_16245", + "serial": "16245", + "code": "JpnL3002", + "identifier": "10730102", + "name": "測試課程 18", + "semester": "1102", + "teacher": "測試教師 2", + "limitation": null, + "note": "note 18", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "preassign", + "language": "zh_TW", + "provider": "ntu", + "slot": 70, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "日文系" + ], + "class": null + }, + { + "id": "1102_31464", + "serial": "31464", + "code": "Thea1104", + "identifier": "10912100", + "name": "測試課程 19", + "semester": "1102", + "teacher": "測試教師 2", + "limitation": null, + "note": "note 19", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 80, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "藝術設計學程", + "", + "亞洲藝術學程" + ], + "class": null + }, + { + "id": "1102_13785", + "serial": "13785", + "code": "ARHY1018", + "identifier": "14111800", + "name": "測試課程 20", + "semester": "1102", + "teacher": "測試教師 2", + "limitation": null, + "note": "note 20", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 60, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "藝術設計學程", + "亞洲藝術學程", + "" + ], + "class": null + }, + { + "id": "1102_44138", + "serial": "44138", + "code": "JpnL3004", + "identifier": "10730202", + "name": "測試課程 21", + "semester": "1102", + "teacher": "測試教師 2", + "limitation": null, + "note": "note 21", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "preassign", + "language": "zh_TW", + "provider": "ntu", + "slot": 70, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "日文系" + ], + "class": null + }, + { + "id": "1102_62127", + "serial": "62127", + "code": "JpnL3012", + "identifier": "10730502", + "name": "測試課程 22", + "semester": "1102", + "teacher": "測試教師 2", + "limitation": null, + "note": "note 22", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "preassign", + "language": "zh_TW", + "provider": "ntu", + "slot": 35, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "日文系" + ], + "class": "02" + }, + { + "id": "1102_76148", + "serial": "76148", + "code": "JpnL3053", + "identifier": "10730532", + "name": "測試課程 23", + "semester": "1102", + "teacher": "測試教師 3", + "limitation": null, + "note": "note 23", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 20, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "日文系" + ], + "class": null + }, + { + "id": "1102_28094", + "serial": "28094", + "code": "TwLit1022", + "identifier": "14510170", + "name": "測試課程 24", + "semester": "1102", + "teacher": "測試教師 3", + "limitation": null, + "note": "note 24", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 36, + "enroll_method": 3, + "intensive_weeks": [], + "departments_raw": [ + "臺灣研究學程", + "" + ], + "class": null + }, + { + "id": "1102_71631", + "serial": "71631", + "code": "MATH2218", + "identifier": "20149700", + "name": "測試課程 25", + "semester": "1102", + "teacher": "測試教師 3", + "limitation": null, + "note": "note 25", + "cool_url": "", + "credits": 4, + "can_be_selective": false, + "is_half_year": true, + "requirement": "preassign", + "language": "zh_TW", + "provider": "ntu", + "slot": 130, + "enroll_method": 3, + "intensive_weeks": [], + "departments_raw": [ + "數學系" + ], + "class": null + }, + { + "id": "1102_49953", + "serial": "49953", + "code": "AtmSci1007", + "identifier": "20912000", + "name": "測試課程 26", + "semester": "1102", + "teacher": "測試教師 3", + "limitation": null, + "note": "note 26", + "cool_url": null, + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 70, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "地科學程", + "" + ], + "class": null + }, + { + "id": "1102_67104", + "serial": "67104", + "code": "ECON2023", + "identifier": "30320060", + "name": "測試課程 27", + "semester": "1102", + "teacher": "測試教師 3", + "limitation": null, + "note": "note 27", + "cool_url": "", + "credits": 4, + "can_be_selective": false, + "is_half_year": true, + "requirement": "required", + "language": "zh_TW", + "provider": "ntu", + "slot": 50, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "經濟系" + ], + "class": "04" + }, + { + "id": "1102_47796", + "serial": "47796", + "code": "ECON4003", + "identifier": "30347500", + "name": "測試課程 28", + "semester": "1102", + "teacher": "測試教師 3", + "limitation": null, + "note": "note 28", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 80, + "enroll_method": 3, + "intensive_weeks": [], + "departments_raw": [ + "經濟系" + ], + "class": "02" + }, + { + "id": "1102_55891", + "serial": "55891", + "code": "ECON4003", + "identifier": "30347500", + "name": "測試課程 29", + "semester": "1102", + "teacher": "測試教師 3", + "limitation": null, + "note": "note 29", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 80, + "enroll_method": 3, + "intensive_weeks": [], + "departments_raw": [ + "經濟系" + ], + "class": "01" + }, + { + "id": "1102_68363", + "serial": "68363", + "code": "Psy5255", + "identifier": "227U5040", + "name": "測試課程 30", + "semester": "1102", + "teacher": "測試教師 4", + "limitation": null, + "note": "note 30", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 48, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "心理所", + "心理系" + ], + "class": null + }, + { + "id": "1102_95129", + "serial": "95129", + "code": "ECON5188", + "identifier": "323EU1090", + "name": "測試課程 31", + "semester": "1102", + "teacher": "測試教師 4", + "limitation": null, + "note": "note 31", + "cool_url": "", + "credits": 1, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 30, + "enroll_method": 1, + "intensive_weeks": [], + "departments_raw": [ + "經濟所", + "經濟系", + "經濟所" + ], + "class": null + }, + { + "id": "1102_52721", + "serial": "52721", + "code": "ECON2021", + "identifier": "30320022", + "name": "測試課程 32", + "semester": "1102", + "teacher": "測試教師 4", + "limitation": null, + "note": "note 32", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "required", + "language": "zh_TW", + "provider": "ntu", + "slot": 120, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "經濟系" + ], + "class": "02" + }, + { + "id": "1102_77199", + "serial": "77199", + "code": "ECON3019", + "identifier": "303E22410", + "name": "測試課程 33", + "semester": "1102", + "teacher": "測試教師 4", + "limitation": null, + "note": "note 33", + "cool_url": null, + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 140, + "enroll_method": 1, + "intensive_weeks": [], + "departments_raw": [ + "經濟系" + ], + "class": null + }, + { + "id": "1102_20169", + "serial": "20169", + "code": "Soc2041", + "identifier": "305E21170", + "name": "測試課程 34", + "semester": "1102", + "teacher": "測試教師 4", + "limitation": null, + "note": "note 34", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 50, + "enroll_method": 1, + "intensive_weeks": [], + "departments_raw": [ + "婦女性別學程", + "社會系", + "人口學程" + ], + "class": null + }, + { + "id": "1102_76808", + "serial": "76808", + "code": "ECON5107", + "identifier": "323EU0260", + "name": "測試課程 35", + "semester": "1102", + "teacher": "測試教師 4", + "limitation": null, + "note": "note 35", + "cool_url": null, + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 30, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "經濟所", + "經濟所", + "經濟系" + ], + "class": null + }, + { + "id": "1102_42441", + "serial": "42441", + "code": "ECON5185", + "identifier": "323EU1260", + "name": "測試課程 36", + "semester": "1102", + "teacher": "測試教師 4", + "limitation": null, + "note": "note 36", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 40, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "經濟所", + "經濟所", + "經濟系" + ], + "class": null + }, + { + "id": "1102_32509", + "serial": "32509", + "code": "ECON2023", + "identifier": "30320060", + "name": "測試課程 37", + "semester": "1102", + "teacher": "測試教師 4", + "limitation": null, + "note": "note 37", + "cool_url": null, + "credits": 4, + "can_be_selective": false, + "is_half_year": true, + "requirement": "required", + "language": "zh_TW", + "provider": "ntu", + "slot": 70, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "經濟系" + ], + "class": "01" + }, + { + "id": "1102_29882", + "serial": "29882", + "code": "ECON2023", + "identifier": "30320060", + "name": "測試課程 38", + "semester": "1102", + "teacher": "測試教師 5", + "limitation": null, + "note": "note 38", + "cool_url": "", + "credits": 4, + "can_be_selective": false, + "is_half_year": true, + "requirement": "required", + "language": "zh_TW", + "provider": "ntu", + "slot": 80, + "enroll_method": 1, + "intensive_weeks": [], + "departments_raw": [ + "經濟系" + ], + "class": "02" + }, + { + "id": "1102_62726", + "serial": "62726", + "code": "NtlDev1084", + "identifier": "34117950", + "name": "測試課程 39", + "semester": "1102", + "teacher": "測試教師 5", + "limitation": null, + "note": "note 39", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 110, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "東亞學分學程", + "" + ], + "class": null + }, + { + "id": "1102_43793", + "serial": "43793", + "code": "ECON2023", + "identifier": "303E20060", + "name": "測試課程 40", + "semester": "1102", + "teacher": "測試教師 5", + "limitation": null, + "note": "note 40", + "cool_url": "", + "credits": 4, + "can_be_selective": false, + "is_half_year": true, + "requirement": "required", + "language": "zh_TW", + "provider": "ntu", + "slot": 60, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "經濟系" + ], + "class": "03" + }, + { + "id": "1102_85244", + "serial": "85244", + "code": "ECON5134", + "identifier": "323U0120", + "name": "測試課程 41", + "semester": "1102", + "teacher": "測試教師 5", + "limitation": null, + "note": "note 41", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 150, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "經濟所", + "經濟系", + "經濟所" + ], + "class": null + }, + { + "id": "1102_74566", + "serial": "74566", + "code": "Tox5009", + "identifier": "447U2500", + "name": "測試課程 42", + "semester": "1102", + "teacher": "測試教師 5", + "limitation": null, + "note": "note 42", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "other", + "language": "zh_TW", + "provider": "ntu", + "slot": 250, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "", + "分子醫藥學程" + ], + "class": null + }, + { + "id": "1102_82924", + "serial": "82924", + "code": "ForMed7037", + "identifier": "452M0490", + "name": "測試課程 43", + "semester": "1102", + "teacher": "測試教師 5", + "limitation": null, + "note": "note 43", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "other", + "language": "zh_TW", + "provider": "ntu", + "slot": 130, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "" + ], + "class": null + }, + { + "id": "1102_10388", + "serial": "10388", + "code": "ME5033", + "identifier": "522U7200", + "name": "測試課程 44", + "semester": "1102", + "teacher": "測試教師 5", + "limitation": null, + "note": "note 44", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 40, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "機械系", + "機械所" + ], + "class": null + }, + { + "id": "1102_70670", + "serial": "70670", + "code": "ESOE5132", + "identifier": "525U9140", + "name": "測試課程 45", + "semester": "1102", + "teacher": "測試教師 6", + "limitation": null, + "note": "note 45", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 63, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "風電學程", + "工科海洋系", + "工科海洋所" + ], + "class": null + }, + { + "id": "1102_62321", + "serial": "62321", + "code": "FOOD1001", + "identifier": "64110100", + "name": "測試課程 46", + "semester": "1102", + "teacher": "測試教師 6", + "limitation": null, + "note": "note 46", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 250, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "永續資源學程", + "" + ], + "class": null + }, + { + "id": "1102_74433", + "serial": "74433", + "code": "Forest3075", + "identifier": "60539580", + "name": "測試課程 47", + "semester": "1102", + "teacher": "測試教師 6", + "limitation": null, + "note": "note 47", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 400, + "enroll_method": 3, + "intensive_weeks": [], + "departments_raw": [ + "森林環資系", + "" + ], + "class": null + }, + { + "id": "1102_37963", + "serial": "37963", + "code": "LibEdu1020", + "identifier": "H0102000", + "name": "測試課程 48", + "semester": "1102", + "teacher": "測試教師 6", + "limitation": null, + "note": "note 48", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "other", + "language": "zh_TW", + "provider": "ntu", + "slot": 130, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "" + ], + "class": null + }, + { + "id": "1102_72915", + "serial": "72915", + "code": "Prog3002", + "identifier": "P4830200", + "name": "測試課程 49", + "semester": "1102", + "teacher": "測試教師 6", + "limitation": null, + "note": "note 49", + "cool_url": "", + "credits": 2, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 35, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "日本學程", + "" + ], + "class": null + }, + { + "id": "1102_38601", + "serial": "38601", + "code": "Prog5243", + "identifier": "P37U0260", + "name": "測試課程 50", + "semester": "1102", + "teacher": "測試教師 6", + "limitation": null, + "note": "note 50", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 30, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "創意創業學程" + ], + "class": null + }, + { + "id": "1102_85970", + "serial": "85970", + "code": "DS5311", + "identifier": "Z01U0230", + "name": "測試課程 51", + "semester": "1102", + "teacher": "測試教師 6", + "limitation": null, + "note": "note 51", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 20, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "建城所", + "創新學位學程", + "創意創業學程", + "領導學程" + ], + "class": null + }, + { + "id": "1102_49014", + "serial": "49014", + "code": "DS5105", + "identifier": "Z01U0240", + "name": "測試課程 52", + "semester": "1102", + "teacher": "測試教師 6", + "limitation": null, + "note": "note 52", + "cool_url": null, + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 20, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "領導學程", + "創意創業學程", + "創新學位學程" + ], + "class": null + }, + { + "id": "1102_35992", + "serial": "35992", + "code": "DS5217", + "identifier": "Z01U0370", + "name": "測試課程 53", + "semester": "1102", + "teacher": "測試教師 7", + "limitation": null, + "note": "note 53", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntu", + "slot": 25, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "創意創業學程", + "創新學位學程", + "建城所" + ], + "class": null + }, + { + "id": "1102_96134", + "serial": "96134", + "code": "TB10410067", + "identifier": "TBTCG0453", + "name": "測試課程 54", + "semester": "1102", + "teacher": "測試教師 7", + "limitation": null, + "note": "note 54", + "cool_url": "", + "credits": 1, + "can_be_selective": false, + "is_half_year": true, + "requirement": "elective", + "language": "zh_TW", + "provider": "ntust", + "slot": 2, + "enroll_method": 3, + "intensive_weeks": [], + "departments_raw": [ + "" + ], + "class": "01" + }, + { + "id": "1102_16800", + "serial": "16800", + "code": "DS5210", + "identifier": "Z01U0270", + "name": "測試課程 55", + "semester": "1102", + "teacher": "測試教師 7", + "limitation": null, + "note": "note 55", + "cool_url": "", + "credits": 3, + "can_be_selective": false, + "is_half_year": true, + "requirement": "preassign", + "language": "zh_TW", + "provider": "ntu", + "slot": 30, + "enroll_method": 2, + "intensive_weeks": [], + "departments_raw": [ + "創新學位學程", + "創意創業學程" + ], + "class": null + } +] \ No newline at end of file diff --git a/prisma/stubData/departments.json b/prisma/stubData/departments.json new file mode 100644 index 0000000..c2f66c1 --- /dev/null +++ b/prisma/stubData/departments.json @@ -0,0 +1,93 @@ +[ + { + "id": "1040", + "college_id": "1", + "name_short": "哲學系", + "name_full": "哲學系", + "name_alt": "" + }, + { + "id": "1020", + "college_id": "1", + "name_short": "外文系", + "name_full": "外國語文學系", + "name_alt": "" + }, + { + "id": "1070", + "college_id": "1", + "name_short": "日文系", + "name_full": "日本語文學系", + "name_alt": "" + }, + { + "id": "2010", + "college_id": "2", + "name_short": "數學系", + "name_full": "數學系", + "name_alt": "" + }, + { + "id": "2070", + "college_id": "2", + "name_short": "心理系", + "name_full": "心理學系", + "name_alt": "" + }, + { + "id": "3050", + "college_id": "3", + "name_short": "社會系", + "name_full": "社會學系", + "name_alt": "" + }, + { + "id": "3030", + "college_id": "3", + "name_short": "經濟系", + "name_full": "經濟學系", + "name_alt": "" + }, + { + "id": "3100", + "college_id": "3", + "name_short": "社工系", + "name_full": "社會工作學系", + "name_alt": "" + }, + { + "id": "6050", + "college_id": "6", + "name_short": "森林環資系", + "name_full": "森林環境暨資源學系", + "name_alt": "" + }, + { + "id": "5050", + "college_id": "5", + "name_short": "工科海洋系", + "name_full": "工程科學及海洋工程學系", + "name_alt": "" + }, + { + "id": "5020", + "college_id": "5", + "name_short": "機械系", + "name_full": "機械工程學系", + "name_alt": "" + }, + { + "id": "6120", + "college_id": "6", + "name_short": "昆蟲系", + "name_full": "昆蟲學系", + "name_alt": "" + }, + { + "id": "1010", + "college_id": "1", + "name_short": "中文系", + "name_full": "中國文學系", + "name_alt": "" + } +] \ No newline at end of file diff --git a/prisma/stubData/generationTool.js b/prisma/stubData/generationTool.js new file mode 100644 index 0000000..bbcf0cb --- /dev/null +++ b/prisma/stubData/generationTool.js @@ -0,0 +1,140 @@ +import "dotenv-defaults/config"; +import prisma from ".."; +import fs from "fs"; + +async function writeModelData(modelName, data) { + fs.writeFileSync( + `./prisma/stubData/${modelName}.json`, + JSON.stringify(data, null, 2) + ); +} + +const maskedUserIdMap = new Map(); +function getMaskedUserId(userId) { + if (!maskedUserIdMap.has(userId)) { + maskedUserIdMap.set(userId, maskedUserIdMap.size); + } + return `test-user-id-${maskedUserIdMap.get(userId)}`; +} + +async function main() { + // users + const users = await prisma.users.findMany({ take: 10, skip: 50 }); + + // tables + const userTables = await prisma.course_tables.findMany({ + where: { user_id: { in: users.map((u) => u.id) } }, + }); + const guestTable = await prisma.course_tables.findMany({ + where: { + user_id: null, + }, + take: 3, + }); + const courseTables = [...userTables, ...guestTable]; + + // courses + const courseIds = new Set(); + for (const user of users) { + for (const fav of user.favorites) { + courseIds.add(fav); + } + } + for (const table of courseTables) { + for (const course of table.courses) { + courseIds.add(course); + } + } + const courses = await prisma.courses.findMany({ + where: { id: { in: Array.from(courseIds) } }, + }); + + // schedule + const courseSchedules = await prisma.course_schedules.findMany({ + where: { course_id: { in: courses.map((c) => c.id) } }, + }); + + // courseAreas + const courseAreas = await prisma.course_areas.findMany({ + where: { course_id: { in: courses.map((u) => u.id) } }, + }); + + // areas + const areaIds = new Set(); + for (const courseArea of courseAreas) { + areaIds.add(courseArea.area_id); + } + const areas = await prisma.areas.findMany({ + where: { id: { in: Array.from(areaIds) } }, + }); + + // courseDepartment + const courseDepartments = await prisma.course_departments.findMany({ + where: { course_id: { in: Array.from(courseIds) } }, + }); + + // department + const departmentIds = new Set(); + for (const courseDepartment of courseDepartments) { + departmentIds.add(courseDepartment.department_id); + } + for (const user of users) { + departmentIds.add(user.major); + departmentIds.add(user.d_major); + } + departmentIds.delete(null); + const departments = await prisma.departments.findMany({ + where: { id: { in: Array.from(departmentIds) } }, + }); + + // colleage + const colleageIds = new Set(); + for (const department of departments) { + colleageIds.add(department.college_id); + } + const colleges = await prisma.colleges.findMany({ + where: { id: { in: Array.from(colleageIds) } }, + }); + + // mask & write + await writeModelData( + "users", + users.map((u, i) => { + u.name = `Test User ${i}`; + u.id = getMaskedUserId(u.id); + u.email = `user.${i}@ntu.edu.tw`; + u.student_id = `B010101${i}`; + + if (i < 1) { + u.name += " (admin)"; + } + return u; + }) + ); + await writeModelData( + "course_tables", + courseTables.map((ct) => { + if (ct.user_id) { + ct.user_id = getMaskedUserId(ct.user_id); + } + return ct; + }) + ); + await writeModelData( + "courses", + courses.map((c, i) => { + c.name = `測試課程 ${i}`; + c.teacher = `測試教師 ${Math.floor(i / Math.sqrt(courses.length))}`; + c.note = `note ${i}`; + return c; + }) + ); + await writeModelData("course_schedules", courseSchedules); + await writeModelData("course_areas", courseAreas); + await writeModelData("areas", areas); + await writeModelData("course_departments", courseDepartments); + await writeModelData("departments", departments); + await writeModelData("colleges", colleges); +} + +main(); diff --git a/prisma/stubData/index.js b/prisma/stubData/index.js new file mode 100644 index 0000000..77ac333 --- /dev/null +++ b/prisma/stubData/index.js @@ -0,0 +1,137 @@ +import prisma from "../"; +import areas from "./areas.json"; +import colleges from "./colleges.json"; +import courses from "./courses.json"; +import departments from "./departments.json"; +import users from "./users.json"; +import course_tables from "./course_tables.json"; +import course_areas from "./course_areas.json"; +import course_departments from "./course_departments.json"; +import course_schedules from "./course_schedules.json"; + +const Verbose = 0; +// const Verbose = 1; + +const UnregisteredData = { + user_id: "auth0|test-unregistered", + token: "a.a.a", + name: "test-user", + email: "test@test.com", +}; + +class StubDataContainer { + constructor() { + // add all raw data + // NOTE: these should be ordered by dependency relations + // NOTE: we need to hardcode this to get type hint + this.areas = areas; + this.colleges = colleges; + this.courses = courses; + this.departments = departments; + this.users = users; + this.course_tables = course_tables; + this.course_areas = course_areas; + this.course_departments = course_departments; + this.course_schedules = course_schedules; + + // indexing + this._usersById = {}; + this._tokensByUserId = {}; + this._usersByToken = {}; + this.admins = []; + this.normalUsers = []; + for (let i = 0; i < users.length; i++) { + const user = users[i]; + const { id } = user; + const token = `${i}.${i}.${i}`; + this._tokensByUserId[id] = token; + this._usersById[id] = user; + this._usersByToken[token] = user; + + if (this.isUserAdmin(id)) { + this.admins.push(user); + } else { + this.normalUsers.push(user); + } + } + this._guestTables = []; + this._linkedTables = []; + for (const table of this.course_tables) { + if (!table.user_id) { + this._guestTables.push(table); + } else { + this._linkedTables.push(table); + } + } + } + + getAllRaw() { + return { + areas, + colleges, + courses, + departments, + users, + course_tables, + course_areas, + course_departments, + course_schedules, + }; + } + + isUserAdmin(userId) { + const user = this.getUserById(userId); + return user.name.includes("admin"); + } + + getTokenByUserId(userId) { + return this._tokensByUserId[userId]; + } + + getUserByToken(token) { + return this._usersByToken[token]; + } + + getUserById(userId) { + return this._usersById[userId]; + } + + getFirstAdminToken() { + return this.getTokenByUserId(this.admins[0]); + } + + getFirstNormalUserToken() { + return this.getTokenByUserId(this.normalUsers[0]); + } + + getFirstGuestTable() { + return this._guestTables[0]; + } + + getFirstLinkedTable() { + return this._linkedTables[0]; + } + + getUnregisteredData() { + return UnregisteredData; + } +} + +const stubDataContainer = new StubDataContainer(); + +export async function insertStubData() { + for (const [name, data] of Object.entries(stubDataContainer.getAllRaw())) { + Verbose > 0 && console.log(`inserting "${name}", ${data.length} entries`); + await prisma[name].createMany({ data }); + Verbose > 0 && console.log(`Model ${name} injected`); + } +} + +export async function deleteStubData() { + for (const name of Object.keys(stubDataContainer.getAllRaw()).reverse()) { + await prisma[name].deleteMany(); + Verbose > 0 && console.log(`Model ${name} deleted`); + } +} + +export default stubDataContainer; diff --git a/prisma/stubData/users.json b/prisma/stubData/users.json new file mode 100644 index 0000000..9f4dc49 --- /dev/null +++ b/prisma/stubData/users.json @@ -0,0 +1,167 @@ +[ + { + "id": "test-user-id-0", + "name": "Test User 0 (admin)", + "email": "user.0@ntu.edu.tw", + "student_id": "B0101010", + "year": 0, + "major": "1020", + "d_major": null, + "minors": [], + "languages": [], + "favorites": [], + "course_tables": [ + "816f8963-93d6-47ad-b03f-c5205c22b61a" + ], + "history_courses": [] + }, + { + "id": "test-user-id-1", + "name": "Test User 1", + "email": "user.1@ntu.edu.tw", + "student_id": "B0101011", + "year": 0, + "major": null, + "d_major": null, + "minors": [], + "languages": [], + "favorites": [], + "course_tables": [], + "history_courses": [] + }, + { + "id": "test-user-id-2", + "name": "Test User 2", + "email": "user.2@ntu.edu.tw", + "student_id": "B0101012", + "year": 0, + "major": "3100", + "d_major": null, + "minors": [], + "languages": [], + "favorites": [], + "course_tables": [ + "4ad5eba9-f328-49b9-aced-ec48e42a1344" + ], + "history_courses": [] + }, + { + "id": "test-user-id-3", + "name": "Test User 3", + "email": "user.3@ntu.edu.tw", + "student_id": "B0101013", + "year": 0, + "major": null, + "d_major": null, + "minors": [], + "languages": [], + "favorites": [ + "1102_52721", + "1102_71631" + ], + "course_tables": [ + "e9f5c3ad-e5e5-44ee-950e-cd478a6edeba" + ], + "history_courses": [] + }, + { + "id": "test-user-id-4", + "name": "Test User 4", + "email": "user.4@ntu.edu.tw", + "student_id": "B0101014", + "year": 0, + "major": "1070", + "d_major": null, + "minors": [], + "languages": [], + "favorites": [ + "1102_13785", + "1102_31464" + ], + "course_tables": [ + "6a8db590-cb97-4364-a097-e5a9243a13e1" + ], + "history_courses": [] + }, + { + "id": "test-user-id-5", + "name": "Test User 5", + "email": "user.5@ntu.edu.tw", + "student_id": "B0101015", + "year": 0, + "major": "1040", + "d_major": "6120", + "minors": [], + "languages": [], + "favorites": [], + "course_tables": [ + "e4d48a63-93d4-459d-b7ed-997cde2c6d4a" + ], + "history_courses": [] + }, + { + "id": "test-user-id-6", + "name": "Test User 6", + "email": "user.6@ntu.edu.tw", + "student_id": "B0101016", + "year": 0, + "major": null, + "d_major": null, + "minors": [], + "languages": [], + "favorites": [], + "course_tables": [ + "a17d4817-14f0-4bb4-b324-b675218ed5ed" + ], + "history_courses": [] + }, + { + "id": "test-user-id-7", + "name": "Test User 7", + "email": "user.7@ntu.edu.tw", + "student_id": "B0101017", + "year": 0, + "major": "6050", + "d_major": null, + "minors": [], + "languages": [], + "favorites": [], + "course_tables": [ + "8b0d0754-b015-4938-8dc5-1347d83289b1" + ], + "history_courses": [] + }, + { + "id": "test-user-id-8", + "name": "Test User 8", + "email": "user.8@ntu.edu.tw", + "student_id": "B0101018", + "year": 0, + "major": "1020", + "d_major": null, + "minors": [], + "languages": [], + "favorites": [], + "course_tables": [ + "dec39a3b-3c33-4ea8-a851-8629ec86b11e" + ], + "history_courses": [] + }, + { + "id": "test-user-id-9", + "name": "Test User 9", + "email": "user.9@ntu.edu.tw", + "student_id": "B0101019", + "year": 0, + "major": null, + "d_major": null, + "minors": [], + "languages": [], + "favorites": [ + "1102_70670", + "1102_10388" + ], + "course_tables": [], + "history_courses": [] + } +] \ No newline at end of file diff --git a/src/__mocks__/auth.js b/src/__mocks__/auth.js new file mode 100644 index 0000000..980022b --- /dev/null +++ b/src/__mocks__/auth.js @@ -0,0 +1,21 @@ +import "dotenv-defaults/config"; +import StubData from "@/prisma/stubData"; + +export function checkJwt(req, res, next) { + const token = req.get("Authorization")?.split(" ")[1]; + if (token) { + if (token === StubData.getUnregisteredData().token) { + req.user = { + sub: StubData.getUnregisteredData().user_id, + }; + } else { + const user = StubData.getUserByToken(token); + req.user = { + sub: user.id, + }; + } + next(); + } else { + res.status(401).send({ message: "Missing JWT token" }); + } +} diff --git a/src/auth.js b/src/auth.js index 8b18446..122e864 100644 --- a/src/auth.js +++ b/src/auth.js @@ -1,7 +1,6 @@ import jwt from "express-jwt"; import jwksRsa from "jwks-rsa"; -import dotenv from "dotenv-defaults"; -dotenv.config(); +import "dotenv-defaults/config"; const checkJwt = jwt({ secret: jwksRsa.expressJwtSecret({ diff --git a/src/express.js b/src/express.js new file mode 100644 index 0000000..044b011 --- /dev/null +++ b/src/express.js @@ -0,0 +1,27 @@ +import express from "express"; +import apiRouter from "./routes/api"; +import cors from "cors"; + +const app = express(); +app.use(cors()); +app.use(express.json({ limit: "5mb" })); +app.use("/api", apiRouter); + +export function startApp() { + const PORT = process.env.PORT || 5000; + + const p = new Promise((resolve, reject) => { + try { + app.listen(PORT, () => { + console.log(`Server is running on port ${PORT}`); + resolve(); + }); + } catch (err) { + reject(err); + } + }); + + return p; +} + +export { app }; diff --git a/src/prisma/schema.prisma b/src/prisma/schema.prisma deleted file mode 100644 index b2a55f5..0000000 --- a/src/prisma/schema.prisma +++ /dev/null @@ -1,217 +0,0 @@ -generator client { - provider = "prisma-client-js" - previewFeatures = ["fullTextSearch"] -} - -datasource db { - provider = "postgresql" - url = env("POSTGRES_URL") -} - -/// The underlying table does not contain a valid unique identifier and can therefore currently not be handled by the Prisma Client. -model course_areas { - course_id String - area_id String - area area @relation(fields: [area_id], references: [id]) - courses courses @relation(fields: [course_id], references: [id], onDelete: Cascade) - - @@id([course_id, area_id]) -} - -/// The underlying table does not contain a valid unique identifier and can therefore currently not be handled by the Prisma Client. -model course_departments { - course_id String - department_id String - courses courses @relation(fields: [course_id], references: [id], onDelete: Cascade) - department department @relation(fields: [department_id], references: [id]) - - @@id([course_id, department_id]) -} - -/// The underlying table does not contain a valid unique identifier and can therefore currently not be handled by the Prisma Client. -model course_prerequisites { - course_id String - pre_course_id String - courses_course_prerequisites_course_idTocourses courses @relation("course_prerequisites_course_idTocourses", fields: [course_id], references: [id], onDelete: Cascade, map: "course_prerequisites") - courses_course_prerequisites_pre_course_idTocourses courses @relation("course_prerequisites_pre_course_idTocourses", fields: [pre_course_id], references: [id], map: "course_prerequisites_pre") - - @@id([course_id, pre_course_id]) -} - -/// The underlying table does not contain a valid unique identifier and can therefore currently not be handled by the Prisma Client. -model course_schedules { - course_id String - weekday Int - interval String - location String - courses courses @relation(fields: [course_id], references: [id], onDelete: Cascade) - - @@id([course_id, weekday, interval, location]) -} - -/// The underlying table does not contain a valid unique identifier and can therefore currently not be handled by the Prisma Client. -model course_specialties { - course_id String - specialty_id String - courses courses @relation(fields: [course_id], references: [id], onDelete: Cascade) - specialty specialty @relation(fields: [specialty_id], references: [id]) - - @@id([course_id, specialty_id]) -} - -model course_tables { - id String @id - name String - user_id String? - semester String - courses String[] - expire_ts DateTime? @db.Timestamp(6) - users users? @relation(fields: [user_id], references: [id], onUpdate: Restrict) -} - -model courses { - id String @id - serial String? - code String - identifier String - name String - semester String - teacher String? - limitation String? - note String? - cool_url String? - credits Float? - can_be_selective Boolean - is_half_year Boolean - requirement course_requirements - language course_languages - provider course_providers - slot Int - enroll_method Int - intensive_weeks Int[] - departments_raw String[] - class String? - syllabus_url String? - areas course_areas[] - departments course_departments[] - course_enrollinfo course_enrollinfo[] - prerequisites course_prerequisites[] @relation("course_prerequisites_course_idTocourses") - prerequisite_of course_prerequisites[] @relation("course_prerequisites_pre_course_idTocourses") - course_ptt course_ptt[] - course_rating course_rating[] - schedules course_schedules[] - specialties course_specialties[] - course_syllabus course_syllabus? -} - -model users { - id String @id - name String - email String - student_id String? - year Int @default(0) - major String? - d_major String? - minors String[] - favorites String[] - course_tables String[] - history_courses String[] - d_major_dept department? @relation("departmentTousers_d_major", fields: [d_major], references: [id], onDelete: Restrict, onUpdate: Restrict) - major_dept department? @relation("departmentTousers_major", fields: [major], references: [id], onDelete: Restrict, onUpdate: Restrict) - course_tables_course_tablesTousers course_tables[] - - @@unique([id, email, student_id]) -} - -model area { - id String @id(map: "areas_pkey") - code String - name String - course_areas course_areas[] - - @@unique([id, code, name], map: "areas_id_code_name_key") -} - -model college { - id String @id(map: "colleges_pkey") - name String - department department[] - - @@unique([id, name], map: "colleges_id_name_key") -} - -model department { - id String @id(map: "departments_pkey") - college_id String? - name_short String? - name_full String - name_alt String? - college college? @relation(fields: [college_id], references: [id], onDelete: Restrict, onUpdate: Restrict, map: "id") - course_departments course_departments[] - users_departmentTousers_d_major users[] @relation("departmentTousers_d_major") - users_departmentTousers_major users[] @relation("departmentTousers_major") - - @@unique([id, name_full], map: "departments_id_name_full_key") -} - -model specialty { - id String @id(map: "specialties_pkey") - name String - course_specialties course_specialties[] - - @@unique([id, name], map: "specialties_id_name_key") -} - -model course_enrollinfo { - course_id String - content Json? @db.Json - fetch_ts DateTime @db.Timestamp(6) - courses courses @relation(fields: [course_id], references: [id], onDelete: NoAction) - - @@id([course_id, fetch_ts]) -} - -model course_ptt { - course_id String - type Int - content Json? @db.Json - fetch_ts DateTime @db.Timestamp(6) - courses courses @relation(fields: [course_id], references: [id], onDelete: NoAction) - - @@id([course_id, type]) -} - -model course_rating { - course_id String - content Json? @db.Json - fetch_ts DateTime @db.Timestamp(6) - courses courses @relation(fields: [course_id], references: [id], onDelete: NoAction) - - @@id([course_id, fetch_ts]) -} - -model course_syllabus { - course_id String @id - content Json? @db.Json - fetch_ts DateTime @db.Timestamp(6) - courses courses @relation(fields: [course_id], references: [id], onDelete: NoAction) -} - -enum course_languages { - zh_TW @map("zh-TW") - en_US @map("en-US") -} - -enum course_providers { - ntu - ntnu - ntust - other -} - -enum course_requirements { - preassign - required - elective - other -} diff --git a/src/prisma/course_query.js b/src/queries/courses.js similarity index 89% rename from src/prisma/course_query.js rename to src/queries/courses.js index 082498a..169d988 100644 --- a/src/prisma/course_query.js +++ b/src/queries/courses.js @@ -1,16 +1,15 @@ -import { PrismaClient } from "@prisma/client"; -const prisma = new PrismaClient(); +import prisma from "@/prisma"; const course_include_all = { departments: { select: { - department: true, + departments: true, }, }, areas: { select: { area_id: true, - area: { + areas: { select: { name: true, }, @@ -20,7 +19,7 @@ const course_include_all = { specialties: { select: { specialty_id: true, - specialty: { + specialties: { select: { name: true, }, @@ -129,19 +128,19 @@ function generate_course_filter(filter, ids = null) { } async function getCoursesbyIds(ids, doSort = true) { - if(ids.length === 0) { + if (ids.length === 0) { return []; } const courses = await prisma.courses.findMany({ where: { id: { in: ids, - } + }, }, - include: course_include_all + include: course_include_all, }); if (courses) { - if(!doSort) { + if (!doSort) { return courses; } const sortedCourses = ids.map((id) => @@ -153,4 +152,9 @@ async function getCoursesbyIds(ids, doSort = true) { } } -export { course_include_all, course_post_process, generate_course_filter, getCoursesbyIds }; +export { + course_include_all, + course_post_process, + generate_course_filter, + getCoursesbyIds, +}; diff --git a/src/routes/api/index.js b/src/routes/api/index.js new file mode 100644 index 0000000..aeaade7 --- /dev/null +++ b/src/routes/api/index.js @@ -0,0 +1,9 @@ +import { Router } from "express"; +import v1Router from "./v1"; +import v2Router from "./v2"; + +const router = Router(); + +router.use("/v1", v1Router).use("/v2", v2Router); + +export default router; diff --git a/src/routes/api/v1/healthcheck.js b/src/routes/api/v1/healthcheck.js new file mode 100644 index 0000000..e184e41 --- /dev/null +++ b/src/routes/api/v1/healthcheck.js @@ -0,0 +1,11 @@ +import { Router } from "express"; + +// route: "/api/v1/healthcheck" +const router = Router(); + +// API version: 1.0 +router.get("/", (req, res) => { + res.send("OK"); +}); + +export default router; diff --git a/src/routes/api/v1/index.js b/src/routes/api/v1/index.js new file mode 100644 index 0000000..fc0ae4d --- /dev/null +++ b/src/routes/api/v1/index.js @@ -0,0 +1,14 @@ +import { Router } from "express"; +import healthCheckRouter from "./healthcheck"; +import logsRouter from "./logs"; +import socialRouter from "./social"; + +// route: "/api/v1" +const router = Router(); + +router + .use("/healthcheck", healthCheckRouter) + .use("/logs", logsRouter) + .use("/social", socialRouter); + +export default router; diff --git a/src/routes/logs.js b/src/routes/api/v1/logs.js similarity index 86% rename from src/routes/logs.js rename to src/routes/api/v1/logs.js index 6aa9e46..4a17e36 100644 --- a/src/routes/logs.js +++ b/src/routes/api/v1/logs.js @@ -1,7 +1,8 @@ -import express from "express"; -import { sendWebhookMessage } from "../utils/webhook_client"; +import { Router } from "express"; +import { sendWebhookMessage } from "@/src/utils/webhook_client"; -const router = express.Router(); +// route: "/api/v1/logs" +const router = Router(); // API version: 1.0 router.post("/error", async (req, res) => { diff --git a/src/routes/social.js b/src/routes/api/v1/social.js similarity index 96% rename from src/routes/social.js rename to src/routes/api/v1/social.js index 7d1158b..26a4d62 100644 --- a/src/routes/social.js +++ b/src/routes/api/v1/social.js @@ -1,14 +1,13 @@ -import express from "express"; -import Social_posts from "../models/Social_posts"; -import Post_reports from "../models/Post_reports"; -import { PrismaClient } from "@prisma/client"; -import { sendWebhookMessage } from "../utils/webhook_client"; -import { checkJwt } from "../auth"; +import { Router } from "express"; +import Social_posts from "@/src/models/Social_posts"; +import Post_reports from "@/src/models/Post_reports"; +import prisma from "@/prisma"; +import { sendWebhookMessage } from "@/src/utils/webhook_client"; +import { checkJwt } from "@/src/auth"; import { v4 as uuidv4 } from "uuid"; // route: "/api/v1/social" -const router = express.Router(); -const prisma = new PrismaClient(); +const router = Router(); const get_self_vote_status = (post, user_id) => { if (post.upvotes.includes(user_id)) { diff --git a/src/routes/api/v2/__tests__/course_tables.test.js b/src/routes/api/v2/__tests__/course_tables.test.js new file mode 100644 index 0000000..e33acdf --- /dev/null +++ b/src/routes/api/v2/__tests__/course_tables.test.js @@ -0,0 +1,360 @@ +import { v4 as uuidv4 } from "uuid"; +import request from "supertest"; +import StubData from "@/prisma/stubData"; +import { app } from "@/src/express"; +import prisma from "@/prisma"; + +describe("API /v2/course_tables", () => { + describe("GET /", () => { + it("should return all tables", async () => { + const token = StubData.getFirstAdminToken(); + + const res = await request(app) + .get("/api/v2/course_tables") + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(200); + expect(res.body.course_tables.length).toBe(StubData.course_tables.length); + // NOTE: here we assume the tables are not aggregated + expect(res.body.course_tables.map((c) => c.id)).toEqual( + StubData.course_tables.map((c) => c.id) + ); + }); + + it("should be invalid without admin privilege", async () => { + const res = await request(app).get("/api/v2/course_tables"); + + expect(res.statusCode).toBe(403); + }); + }); + + describe("POST /", () => { + const reqData = { + name: "new test table", + }; + + it("should return the created table", async () => { + const res = await request(app) + .post("/api/v2/course_tables") + .send(reqData); + + expect(res.statusCode).toBe(200); + expect(res.body.course_table.id).toEqual(expect.any(String)); + expect(res.body.course_table.semester).toEqual(process.env.SEMESTER); + expect(res.body.course_table.name).toEqual(reqData.name); + }); + + it("should block a request without input", async () => { + const res = await request(app).post("/api/v2/course_tables"); + + expect(res.statusCode).toBe(400); + }); + + it("should block a request with empty name", async () => { + const res = await request(app) + .post("/api/v2/course_tables") + .send({ name: "" }); + + expect(res.statusCode).toBe(400); + }); + + it("should create a table in db", async () => { + const res = await request(app) + .post("/api/v2/course_tables") + .send(reqData); + + expect(res.statusCode).toBe(200); + + const table = prisma.course_tables.findUnique({ + where: { id: res.body.course_table.id }, + }); + expect(table?.name).toEqual(reqTable.name); + expect(table?.courses).toEqual([]); + }); + }); + + describe("GET /:id", () => { + it("should return the selected table", async () => { + const guestTable = StubData.getFirstGuestTable(); + const res = await request(app).get( + `/api/v2/course_tables/${guestTable.id}` + ); + + expect(res.statusCode).toBe(200); + expect(res.body.course_table?.id).toEqual(guestTable.id); + expect(res.body.course_table?.name).toEqual(guestTable.name); + expect(res.body.course_table?.courses.length).toEqual( + guestTable.courses.length + ); + }); + + it("should allow owner to get their tables", async () => { + const linkedTable = StubData.getFirstLinkedTable(); + const token = StubData.getTokenByUserId(linkedTable.user_id); + const res = await request(app) + .get(`/api/v2/course_tables/${linkedTable.id}`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(200); + expect(res.body.course_table?.id).toEqual(linkedTable.id); + expect(res.body.course_table?.name).toEqual(linkedTable.name); + expect(res.body.course_table?.courses.length).toEqual( + linkedTable.courses.length + ); + }); + + it("should block guests to get other's tables", async () => { + const linkedTable = StubData.getFirstLinkedTable(); + const res = await request(app).get( + `/api/v2/course_tables/${linkedTable.id}` + ); + + expect(res.statusCode).toBe(403); + }); + + it("should block users to get other's tables", async () => { + const linkedTable = StubData.getFirstLinkedTable(); + const anotherNormalUser = StubData.users.find( + (u) => !StubData.isUserAdmin(u.id) && u.id !== linkedTable.user_id + ); + const token = StubData.getTokenByUserId(anotherNormalUser.id); + const res = await request(app) + .get(`/api/v2/course_tables/${linkedTable.id}`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(403); + }); + + it("should response 404 to a request with unknown id", async () => { + const res = await request(app).get( + `/api/v2/course_tables/unkown_table_id` + ); + + expect(res.statusCode).toBe(404); + }); + }); + + describe("DELETE /:id", () => { + const [user1, user2] = StubData.normalUsers.slice(0, 2); + const token1 = StubData.getTokenByUserId(user1.id); + const token2 = StubData.getTokenByUserId(user2.id); + const tableTemplate = { + id: uuidv4(), + name: "temp table", + semester: process.env.SEMESTER, + user_id: user1.id, + courses: [], + }; + + beforeEach(async () => { + await prisma.course_tables.create({ data: tableTemplate }); + }); + + it("should block guests to delete other's tables", async () => { + const res = await request(app).delete( + `/api/v2/course_tables/${tableTemplate.id}` + ); + + expect(res.statusCode).toBe(401); + + const resTable = await prisma.course_tables.findUnique({ + where: { id: tableTemplate.id }, + }); + expect(resTable?.name).toBe(tableTemplate.name); + }); + + it("should block users to delete other's tables", async () => { + const res = await request(app) + .delete(`/api/v2/course_tables/${tableTemplate.id}`) + .set("Authorization", `Bearer ${token2}`); + + expect(res.statusCode).toBe(403); + + const resTable = await prisma.course_tables.findUnique({ + where: { id: tableTemplate.id }, + }); + expect(resTable?.name).toBe(tableTemplate.name); + }); + + it("should response 404 to a request with unknown table id", async () => { + const res = await request(app) + .delete(`/api/v2/course_tables/unknown_table_id`) + .set("Authorization", `Bearer ${token2}`); + + expect(res.statusCode).toBe(404); + + const resTable = await prisma.course_tables.findUnique({ + where: { id: tableTemplate.id }, + }); + expect(resTable?.name).toBe(tableTemplate.name); + }); + + it("should delete tables in db", async () => { + const res = await request(app) + .delete(`/api/v2/course_tables/${tableTemplate.id}`) + .set("Authorization", `Bearer ${token1}`); + + expect(res.statusCode).toBe(200); + + const resTable = await prisma.course_tables.findUnique({ + where: { id: tableTemplate.id }, + }); + expect(resTable).toBe(null); + }); + + afterEach(async () => { + // hackfix: using `deleteMany` to delete records that may not exists + await prisma.course_tables.deleteMany({ + where: { id: tableTemplate.id }, + }); + }); + }); + + describe("PATCH /:id", () => { + const [user1, user2] = StubData.normalUsers.slice(0, 2); + const token1 = StubData.getTokenByUserId(user1.id); + const token2 = StubData.getTokenByUserId(user2.id); + const tableTemplate = { + id: uuidv4(), + name: "temp table", + semester: process.env.SEMESTER, + user_id: user1.id, + courses: [], + }; + + const newName = "new temp table"; + const newCourses = StubData.courses.slice(0, 3).map((c) => c.id); + + beforeEach(async () => { + await prisma.course_tables.create({ data: tableTemplate }); + }); + + it("should return the updated table", async () => { + const res = await request(app) + .patch(`/api/v2/course_tables/${tableTemplate.id}`) + .set("Authorization", `Bearer ${token1}`) + .send({ + courses: newCourses, + }); + + expect(res.statusCode).toBe(200); + expect(res?.body.course_table.name).toEqual(tableTemplate.name); + expect(res?.body.course_table.courses.map((c) => c.id)).toEqual( + newCourses + ); + }); + + it("should block guests to update other's tables", async () => { + const res = await request(app) + .patch(`/api/v2/course_tables/${tableTemplate.id}`) + .send({ + courses: newCourses, + }); + + expect(res.statusCode).toBe(401); + + const resTable = await prisma.course_tables.findUnique({ + where: { id: tableTemplate.id }, + }); + expect(resTable?.name).toBe(tableTemplate.name); + expect(resTable?.courses).toEqual(tableTemplate.courses); + }); + + it("should block users to update other's tables", async () => { + const res = await request(app) + .patch(`/api/v2/course_tables/${tableTemplate.id}`) + .set("Authorization", `Bearer ${token2}`) + .send({ + courses: newCourses, + }); + + expect(res.statusCode).toBe(403); + + const resTable = await prisma.course_tables.findUnique({ + where: { id: tableTemplate.id }, + }); + expect(resTable?.name).toBe(tableTemplate.name); + expect(resTable?.courses).toEqual(tableTemplate.courses); + }); + + it("should response 404 to a request with unknown table id", async () => { + const res = await request(app) + .patch(`/api/v2/course_tables/unknown_table_id`) + .set("Authorization", `Bearer ${token2}`) + .send({ + courses: newCourses, + }); + + expect(res.statusCode).toBe(404); + + const resTable = await prisma.course_tables.findUnique({ + where: { id: tableTemplate.id }, + }); + expect(resTable?.name).toBe(tableTemplate.name); + expect(resTable?.courses).toEqual(tableTemplate.courses); + }); + + it("should block a request with no update data", async () => { + const res = await request(app) + .patch(`/api/v2/course_tables/${tableTemplate.id}`) + .set("Authorization", `Bearer ${token1}`); + + expect(res.statusCode).toBe(400); + }); + + it("should block a request with invalid course id", async () => { + const res = await request(app) + .patch(`/api/v2/course_tables/${tableTemplate.id}`) + .set("Authorization", `Bearer ${token1}`) + .send({ + courses: ["unknown_course_id", ...newCourses], + }); + + expect(res.statusCode).toBe(400); + + const resTable = await prisma.course_tables.findUnique({ + where: { id: tableTemplate.id }, + }); + expect(resTable?.name).toBe(tableTemplate.name); + expect(resTable?.courses).toEqual(tableTemplate.courses); + }); + + it("should update table name in db", async () => { + const res = await request(app) + .patch(`/api/v2/course_tables/${tableTemplate.id}`) + .set("Authorization", `Bearer ${token1}`) + .send({ + name: newName, + }); + + expect(res.statusCode).toBe(200); + + const resTable = await prisma.course_tables.findUnique({ + where: { id: tableTemplate.id }, + }); + expect(resTable?.name).toBe(newName); + expect(resTable?.courses).toEqual(tableTemplate.courses); + }); + + it("should update table courses in db", async () => { + const res = await request(app) + .patch(`/api/v2/course_tables/${tableTemplate.id}`) + .set("Authorization", `Bearer ${token1}`) + .send({ + courses: newCourses, + }); + + expect(res.statusCode).toBe(200); + + const resTable = await prisma.course_tables.findUnique({ + where: { id: tableTemplate.id }, + }); + expect(resTable?.name).toBe(tableTemplate.name); + expect(resTable?.courses).toEqual(newCourses); + }); + + afterEach(async () => { + await prisma.course_tables.delete({ where: { id: tableTemplate.id } }); + }); + }); +}); diff --git a/src/routes/api/v2/__tests__/courses.test.js b/src/routes/api/v2/__tests__/courses.test.js new file mode 100644 index 0000000..e29acec --- /dev/null +++ b/src/routes/api/v2/__tests__/courses.test.js @@ -0,0 +1,147 @@ +import request from "supertest"; +import StubData from "@/prisma/stubData"; +import { app } from "@/src/express"; + +describe("API /v2/courses", () => { + describe("GET /", () => { + it("should return all courses", async () => { + const token = StubData.getFirstAdminToken(); + const res = await request(app) + .get("/api/v2/courses") + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(200); + expect(res.body.courses.length).toBe(StubData.courses.length); + expect(res.body.courses.map((c) => c.name)).toBe( + StubData.courses.map((c) => c.name) + ); + }); + + it("should be invalid without admin privilege", async () => { + const res = await request(app).get("/api/v2/courses"); + + expect(res.statusCode).toBe(403); + }); + }); + + describe("POST /search", () => { + const CompleteRequestObject = { + keyword: "專題研究", + fields: ["name"], + filter: { + strict_match: false, + time: [["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "A", "B"]], + department: ["5050"], + category: ["test"], + enroll_method: ["1", "2", "3"], + }, + batch_size: 5, + offset: 0, + }; + + it("should support search by name", async () => { + const res = await request(app) + .post("/api/v2/courses/search") + .send(CompleteRequestObject); + + expect(res.statusCode).toBe(200); + expect(res.body.courses.length > 0).toBeTruthy(); + // console.log(res.body); + // TODO: check content + }); + + // TODO: add more search condition checks + + it("should response invalid requests with 400", async () => { + for (const key of Object.keys(CompleteRequestObject)) { + const badRequestObject = { + ...CompleteRequestObject, + }; + delete badRequestObject[key]; + const res = await request(app) + .post("/api/v2/courses/search") + .send(CompleteRequestObject); + + expect(res.statusCode).toBe(400); + } + }); + }); + + describe("POST /ids", () => { + const SomeCourse = StubData.courses.slice(0, 3); + const SomeCourseIds = SomeCourse.map((c) => c.id); + + it("should return the selected courses", async () => { + const res = await request(app).post("/api/v2/courses/ids").send({ + ids: SomeCourseIds, + }); + + expect(res.statusCode).toBe(200); + expect(res.body.courses.length).toBe(SomeCourseIds.length); + expect(res.body.courses[0].name).toBe(SomeCourse[0].name); + }); + + it("should block a request with any unknown id", async () => { + const res = await request(app) + .post("/api/v2/courses/ids") + .send({ + ids: ["unknown_id_1", ...SomeCourseIds], + }); + + expect(res.statusCode).toBe(400); + }); + + it("should block a request with too many id", async () => { + const res = await request(app) + .post("/api/v2/courses/ids") + .send({ + ids: Array(process.env.COURSE_REQUEST_LIMIT + 1).fill( + StubData.courses[0].id + ), + }); + + expect(res.statusCode).toBe(400); + }); + }); + + describe("Get /:id", () => { + it("should return the selected courses", async () => { + const course = StubData.courses[0]; + const res = await request(app).get(`/api/v2/courses/${course.id}`); + + expect(res.statusCode).toBe(200); + expect(res.body.course.name).toBe(course.name); + expect(res.body.course.id).toBe(course.id); + }); + + it("should response 404 to a request with unknown id", async () => { + const res = await request(app).get(`/api/v2/courses/unknown_course_id`); + + expect(res.statusCode).toBe(404); + }); + }); + + // TODO: add live api support for `/:serial/enrollinfo`, `/:id/rating` , `/:id/ptt/:board`, `/:id/syllabus` + + // describe("Get /:course_id/syllabus", () => { + // it("should return the syllabus for the selected course", async () => { + // const course = StubData.courses[0]; + // const res = await request(app).get( + // `/api/v2/courses/${course.id}/syllabus` + // ); + + // expect(res.statusCode).toBe(200); + // expect(res.body.course_id).toBe(course.id); + // expect(res.body.course_syllabus?.syllabus).toEqual(expect.anything()); + // expect(res.body.course_syllabus?.grade).toEqual(expect.anything()); + // }); + + // it("should response 404 to a request with unknown id", async () => { + // const res = await request(app).get( + // `/api/v2/courses/unknown_course_id/syllabus` + // ); + + // expect(res.statusCode).toBe(404); + // }); + // }); +}); diff --git a/src/routes/api/v2/__tests__/users.test.js b/src/routes/api/v2/__tests__/users.test.js new file mode 100644 index 0000000..c04129d --- /dev/null +++ b/src/routes/api/v2/__tests__/users.test.js @@ -0,0 +1,384 @@ +import request from "supertest"; +import StubData from "@/prisma/stubData"; +import { app } from "@/src/express"; +import prisma from "@/prisma"; + +describe("API /v2/users", () => { + describe("GET /:id", () => { + it("should return the selected user", async () => { + const user = StubData.normalUsers[0]; + const token = StubData.getTokenByUserId(user.id); + + const res = await request(app) + .get(`/api/v2/users/${user.id}`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(200); + expect(res.body.user?.db?.id).toBe(user.id); + expect(res.body.user?.db?.name).toBe(user.name); + expect(res.body.user?.db?.email).toBe(user.email); + + // TODO: add more content tests + }); + + it("should only be available to user themself", async () => { + const [user1, user2] = StubData.normalUsers.slice(0, 2); + const token = StubData.getTokenByUserId(user1.id); + + const res = await request(app) + .get(`/api/v2/users/${user2.id}`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(403); + }); + + it("should response 404 to a request with unknown id", async () => { + const user = StubData.normalUsers[0]; + const token = StubData.getTokenByUserId(user.id); + + const res = await request(app) + .get(`/api/v2/users/unknown_user_id`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(404); + }); + }); + + describe("POST /", () => { + it("should return the created user", async () => { + const { + user_id: id, + name, + email, + token, + } = StubData.getUnregisteredData(); + + const res = await request(app) + .post(`/api/v2/users`) + .set("Authorization", `Bearer ${token}`) + .send({ user: { email } }); + + expect(res.statusCode).toBe(200); + expect(res.body.user?.db?.id).toBe(id); + expect(res.body.user?.db?.name).toBe(name); + expect(res.body.user?.db?.email).toBe(email); + }); + + it("should block a request with unmatched email", async () => { + const { email } = StubData.getUnregisteredData(); + const token = StubData.getFirstNormalUserToken(); + + const res = await request(app) + .post(`/api/v2/users`) + .set("Authorization", `Bearer ${token}`) + .send({ user: { email } }); + + expect(res.statusCode).toBe(403); + }); + + it("should block a request with empty body", async () => { + const { token } = StubData.getUnregisteredData(); + + const res = await request(app) + .post(`/api/v2/users`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(400); + }); + + it("should create a new user in db", async () => { + const { + user_id: id, + name, + email, + token, + } = StubData.getUnregisteredData(); + + const res = await request(app) + .get(`/api/v2/users`) + .set("Authorization", `Bearer ${token}`) + .send({ user: { email } }); + + expect(res.statusCode).toBe(200); + + const resUser = await prisma.users.findUnique({ where: { id } }); + expect(resUser?.name).toBe(name); + expect(resUser?.email).toBe(email); + }); + + afterEach(async () => { + await prisma.users.deleteMany({ + where: { id: StubData.getUnregisteredData().user_id }, + }); + }); + }); + + describe("PATCH /", () => { + const { user_id: id, name, email, token } = StubData.getUnregisteredData(); + const userTemplate = { id, name, email, year: 0 }; + const newUserYear = 5; + + beforeEach(async () => { + await prisma.users.create({ data: userTemplate }); + }); + + it("should return the updated user", async () => { + const res = await request(app) + .patch(`/api/v2/users`) + .set("Authorization", `Bearer ${token}`) + .send({ user: { year: newUserYear } }); + + expect(res.statusCode).toBe(200); + expect(res.body.user?.db?.id).toBe(id); + expect(res.body.user?.db?.name).toBe(name); + expect(res.body.user?.db?.email).toBe(email); + expect(res.body.user?.db?.year).toBe(newUserYear); + + // TODO: test other fields + }); + + describe("should block a request with invalid fields", () => { + const invalidFileds = { + id: "test_id", + email: "test@gmail.com", + student_id: "B01234567", + }; + + it.each(Object.entries(invalidFileds))( + "{ %p: %p }", + async (key, value) => { + const res = await request(app) + .patch(`/api/v2/users`) + .set("Authorization", `Bearer ${token}`) + .send({ user: { [key]: value } }); + + expect(res.statusCode).toBe(400); + } + ); + }); + + describe("should block a request with wrong data type", () => { + const wrongFields = { + name: 0, + year: "1", + major: 0, + d_major: 0, + minors: 0, + languages: 0, + favorites: 0, + }; + + it.each(Object.entries(wrongFields))("{ %p: %p }", async (key, value) => { + const res = await request(app) + .patch(`/api/v2/users`) + .set("Authorization", `Bearer ${token}`) + .send({ user: { [key]: value } }); + + console.log(res.body); + expect(res.statusCode).toBe(400); + }); + }); + + it("should block guests to update other's user data", async () => { + const res = await request(app) + .patch(`/api/v2/users`) + .send({ user: { year: newUserYear } }); + + expect(res.statusCode).toBe(401); + const resUser = await prisma.users.findUnique({ where: { id } }); + expect(resUser?.year).toBe(userTemplate.year); + }); + + it("should block users to update other's user data", async () => { + const normalUserToken = StubData.getFirstNormalUserToken(); + + const res = await request(app) + .patch(`/api/v2/users`) + .set("Authorization", `Bearer ${normalUserToken}`) + .send({ user: { year: newUserYear } }); + + expect(res.statusCode).toBe(403); + const resUser = await prisma.users.findUnique({ where: { id } }); + expect(resUser?.year).toBe(userTemplate.year); + }); + + it("should update users in db", async () => { + const res = await request(app) + .patch(`/api/v2/users`) + .set("Authorization", `Bearer ${token}`) + .send({ user: { year: newUserYear } }); + + expect(res.statusCode).toBe(200); + const resUser = await prisma.users.findUnique({ where: { id } }); + expect(resUser?.year).toBe(newUserYear); + + // TODO: test other fields + }); + + afterEach(async () => { + await prisma.users.deleteMany({ + where: { id: StubData.getUnregisteredData().user_id }, + }); + }); + }); + + // NOTE: skipped `POST /v2/users/:id/course_table` since it should be removed in the next version + + describe("DELETE /:type", () => { + const { user_id: id, name, email, token } = StubData.getUnregisteredData(); + const userTemplate = { id, name, email }; + + it("should block a request with unknown target type", async () => { + const res = await request(app) + .delete(`/api/v2/users/unknown_type`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(404); + }); + + it.each(["account", "profile"])( + "should block guests to delete their data", + async (type) => { + const res = await request(app) + .delete(`/api/v2/users/${type}`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(401); + } + ); + + it("should delete the user in db", async () => { + await prisma.users.create({ data: userTemplate }); + + const res = await request(app) + .delete(`/api/v2/users`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(200); + + const resUser = await prisma.users.findUnique({ where: { id } }); + expect(resUser).toBe(null); + }); + + // TODO: test deleting in auth0 api (`DELETE /account`) + + afterEach(async () => { + await prisma.users.deleteMany({ + where: { id }, + }); + }); + }); + + describe("PUT /favorites/:course_id", () => { + const { user_id: id, name, email, token } = StubData.getUnregisteredData(); + const userTemplate = { id, name, email }; + const newCourseId = StubData.courses[0].id; + + beforeEach(async () => { + await prisma.users.create({ data: userTemplate }); + }); + + it("should return the updated favorite courses", async () => { + const res = await request(app) + .put(`/api/v2/users/favorites/${newCourseId}`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(200); + expect(res.body.favorites?.length).toBe(1); + expect(res.body.favorites?.[0]?.id).toBe(newCourseId); + }); + + it("should block a request with unknown course id", async () => { + const res = await request(app) + .put(`/api/v2/users/favorites/unknown_course_id`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(400); + }); + + it("should block a request with course id already in favorites", async () => { + await prisma.users.update({ + where: { id }, + data: { favorites: [newCourseId] }, + }); + + const res = await request(app) + .put(`/api/v2/users/favorites/${newCourseId}`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(400); + }); + + it("should update favorite courses in db", async () => { + const res = await request(app) + .put(`/api/v2/users/favorites/${newCourseId}`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(200); + + const resUser = await prisma.users.findUnique({ where: { id } }); + expect(resUser?.favorites?.length).toBe(1); + expect(resUser?.favorites?.[0]).toBe(newCourseId); + }); + + afterEach(async () => { + await prisma.users.deleteMany({ + where: { id }, + }); + }); + }); + + describe("DELETE /favorites/:course_id", () => { + const { user_id: id, name, email, token } = StubData.getUnregisteredData(); + const newCourseId = StubData.courses[0].id; + const userTemplate = { id, name, email, favorites: [newCourseId] }; + + beforeEach(async () => { + await prisma.users.create({ data: userTemplate }); + }); + + it("should return the updated favorite courses", async () => { + const res = await request(app) + .delete(`/api/v2/users/favorites/${newCourseId}`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(200); + expect(res.body.favorites?.length).toBe(0); + }); + + it("should block a request with unknown course id", async () => { + const res = await request(app) + .delete(`/api/v2/users/favorites/unknown_course_id`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(400); + }); + + it("should block a request with course id not in favorites", async () => { + const secondCourseId = StubData.courses[1].id; + + const res = await request(app) + .delete(`/api/v2/users/favorites/${secondCourseId}`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(400); + }); + + it("should update favorite courses in db", async () => { + const res = await request(app) + .delete(`/api/v2/users/favorites/${newCourseId}`) + .set("Authorization", `Bearer ${token}`); + + expect(res.statusCode).toBe(200); + + const resUser = await prisma.users.findUnique({ where: { id } }); + expect(resUser?.favorites?.length).toBe(0); + }); + + afterEach(async () => { + await prisma.users.deleteMany({ + where: { id }, + }); + }); + }); +}); diff --git a/src/routes/course_tables.js b/src/routes/api/v2/course_tables.js similarity index 93% rename from src/routes/course_tables.js rename to src/routes/api/v2/course_tables.js index b60a769..4cdfcda 100644 --- a/src/routes/course_tables.js +++ b/src/routes/api/v2/course_tables.js @@ -1,12 +1,12 @@ -import express from "express"; -import { PrismaClient } from "@prisma/client"; -import { sendWebhookMessage } from "../utils/webhook_client"; -import { checkJwt } from "../auth"; -import * as auth0_client from "../utils/auth0_client"; -import { getCoursesbyIds } from "../prisma/course_query"; +import { Router } from "express"; +import prisma from "@/prisma"; +import { sendWebhookMessage } from "@/src/utils/webhook_client"; +import { checkJwt } from "@/src/auth"; +import * as auth0_client from "@/src/utils/auth0_client"; +import { getCoursesbyIds } from "@/src/queries/courses"; -const prisma = new PrismaClient(); -const router = express.Router(); +// route: "/api/v2/course_tables" +const router = Router(); const active_semester = process.env.SEMESTER; const check_is_admin = async (user_id) => { @@ -27,9 +27,10 @@ router.get("/", checkJwt, async (req, res) => { let result; try { result = await prisma.course_tables.findMany(); - res - .status(200) - .send({ course_table: result, message: "Get full course table package" }); + res.status(200).send({ + course_tables: result, + message: "Get full course table package", + }); console.log("Get full course table package."); } catch (err) { res.status(500).send({ coures_table: null, message: err }); @@ -100,6 +101,7 @@ router.get("/:id", async (req, res) => { // API version: 2.0 router.post("/", async (req, res) => { + // TODO: spawn uuid in backend instead of using frontend input const course_table_id = req.body.id; const course_table_name = req.body.name; const user_id = req.body.user_id; diff --git a/src/routes/courses.js b/src/routes/api/v2/courses.js similarity index 93% rename from src/routes/courses.js rename to src/routes/api/v2/courses.js index 62c0a45..2e002df 100644 --- a/src/routes/courses.js +++ b/src/routes/api/v2/courses.js @@ -1,12 +1,18 @@ -import express from "express"; +import { Router } from "express"; import axios from "axios"; -import { checkJwt } from "../auth"; -import { Prisma, PrismaClient } from "@prisma/client"; -import { sendWebhookMessage } from "../utils/webhook_client"; -import { course_include_all, course_post_process, generate_course_filter, getCoursesbyIds } from "../prisma/course_query"; +import { checkJwt } from "@/src/auth"; +import { Prisma } from "@prisma/client"; +import prisma from "@/prisma"; +import { sendWebhookMessage } from "@/src/utils/webhook_client"; +import { + course_include_all, + course_post_process, + generate_course_filter, + getCoursesbyIds, +} from "@/src/queries/courses"; -const router = express.Router(); -const prisma = new PrismaClient(); +// route: "/api/v2/courses" +const router = Router(); // API version: 2.0 router.get("/", async (req, res) => { @@ -38,10 +44,19 @@ router.get("/", async (req, res) => { // API version: 2.0 router.post("/search", async (req, res) => { - const { keyword, fields, filter, batch_size, offset } = req.body; - const valid_keyword_fields = ["name", "teacher", "serial", "code", "identifier"]; - const active_semester = process.env.SEMESTER - if(!fields || fields.map((field) => valid_keyword_fields.includes(field)).includes(false)) { + const { keyword, fields, filter, batch_size, offset, semester } = req.body; + const valid_keyword_fields = [ + "name", + "teacher", + "serial", + "code", + "identifier", + ]; + const active_semester = process.env.SEMESTER; + if ( + !fields || + fields.map((field) => valid_keyword_fields.includes(field)).includes(false) + ) { res.status(400).send({ message: "Invalid keyword fields." }); return; } @@ -69,7 +84,7 @@ router.post("/search", async (req, res) => { } conditions.AND.push({ semester: { - equals: active_semester, + equals: semester ?? active_semester, }, }); const courses = await prisma.courses.findMany(find_object); @@ -117,7 +132,10 @@ router.post("/ids", async (req, res) => { } try { const courses = await getCoursesbyIds(ids, sorted == null ? true : sorted); - res.status(200).send({ courses: course_post_process(courses), total_count: courses.length }); + res.status(200).send({ + courses: course_post_process(courses), + total_count: courses.length, + }); } catch (err) { console.error(err); res.status(500).send({ message: err }); diff --git a/src/routes/api/v2/index.js b/src/routes/api/v2/index.js new file mode 100644 index 0000000..59a4700 --- /dev/null +++ b/src/routes/api/v2/index.js @@ -0,0 +1,14 @@ +import { Router } from "express"; +import courseTableRouter from "./course_tables"; +import coursesRouter from "./courses"; +import usersRouter from "./users"; + +// route: "/api/v2" +const router = Router(); + +router + .use("/course_tables", courseTableRouter) + .use("/courses", coursesRouter) + .use("/users", usersRouter); + +export default router; diff --git a/src/routes/users.js b/src/routes/api/v2/users.js similarity index 96% rename from src/routes/users.js rename to src/routes/api/v2/users.js index 91a7db3..01681b4 100644 --- a/src/routes/users.js +++ b/src/routes/api/v2/users.js @@ -1,12 +1,12 @@ -import express from "express"; -import * as auth0_client from "../utils/auth0_client"; -import { PrismaClient } from "@prisma/client"; -import { checkJwt } from "../auth"; -import { sendWebhookMessage } from "../utils/webhook_client"; -import { getCoursesbyIds } from "../prisma/course_query"; +import { Router } from "express"; +import * as auth0_client from "@/src/utils/auth0_client"; +import prisma from "@/prisma"; +import { checkJwt } from "@/src/auth"; +import { sendWebhookMessage } from "@/src/utils/webhook_client"; +import { getCoursesbyIds } from "@/src/queries/courses"; -const router = express.Router(); -const prisma = new PrismaClient(); +// route: "/api/v2/users" +const router = Router(); // API version: 2.0 router.get("/:id", checkJwt, async (req, res) => { @@ -56,9 +56,9 @@ router.get("/:id", checkJwt, async (req, res) => { // API version: 2.0 // Checks Auth0 user instance. router.post("/", checkJwt, async (req, res) => { - const email = req.body.user.email; - const token_sub = req.user.sub; try { + const email = req.body.user.email; + const token_sub = req.user.sub; if (!email) { res.status(400).send({ message: "email is required", user: null }); return; @@ -466,7 +466,7 @@ async function process_user_info(user) { } } const minor_codes = JSON.parse(JSON.stringify(user.minors)); - user.minors = await prisma.department.findMany({ + user.minors = await prisma.departments.findMany({ where: { id: { in: minor_codes, diff --git a/src/routes/index.js b/src/routes/index.js deleted file mode 100644 index b06368b..0000000 --- a/src/routes/index.js +++ /dev/null @@ -1,10 +0,0 @@ -import express from "express"; - -const router = express.Router(); - -// API version: 1.0 -router.get("/healthcheck", (req, res) => { - res.send("OK"); -}); - -export default router; diff --git a/src/server.js b/src/server.js index 1f67661..33c742e 100644 --- a/src/server.js +++ b/src/server.js @@ -1,33 +1,21 @@ -import express from "express"; -import dotenv from "dotenv-defaults"; -import router from "./routes/index"; -import course_router from "./routes/courses"; -import user_router from "./routes/users"; -import course_table_router from "./routes/course_tables"; -import social_router from "./routes/social"; -import logs_router from "./routes/logs"; -import cors from "cors"; +import "dotenv-defaults/config"; import mongoose from "mongoose"; +import { startApp } from "./express"; -const app = express(); -dotenv.config(); +async function main() { + try { + // mongoose + await mongoose.connect(process.env.MONGO_URL, { + useNewUrlParser: true, + useUnifiedTopology: true, + }); + console.log("mongo db connection created"); -app.use(cors()); -app.use(express.json({ limit: "5mb" })); -app.use("/api/v1", router); -app.use("/api/v2/courses", course_router); -app.use("/api/v2/course_tables", course_table_router); -app.use("/api/v2/users", user_router); -app.use("/api/v1/social", social_router); -app.use("/api/v1/logs", logs_router); + // express + await startApp(); + } catch (err) { + console.error(err); + } +} -mongoose - .connect(process.env.MONGO_URL, { - useNewUrlParser: true, - useUnifiedTopology: true, - }) - .then((res) => console.log("mongo db connection created")); - -app.listen(5000 || process.env.PORT, () => { - console.log("Server is running on port 5000"); -}); +main(); diff --git a/src/utils/__mocks__/auth0_client.js b/src/utils/__mocks__/auth0_client.js new file mode 100644 index 0000000..4e77036 --- /dev/null +++ b/src/utils/__mocks__/auth0_client.js @@ -0,0 +1,51 @@ +import { AxiosError } from "axios"; +import "dotenv-defaults/config"; +import StubData from "@/prisma/stubData"; + +const MockedToken = `MockedTokenForTesting`; + +export async function get_token() { + return MockedToken; +} + +function checkAccessToken(token) { + if (token !== MockedToken) { + throw new AxiosError(`Invalid authorization token`, "401"); + } +} + +export async function get_user_by_email(email, token) { + checkAccessToken(token); + + if (email === StubData.getUnregisteredData().email) { + return [StubData.getUnregisteredData()]; + } + + return []; +} + +export async function get_user_by_id(id, token) { + checkAccessToken(token); + + // Not used in test currently + return null; +} + +export async function delete_user_by_id(id, token) { + checkAccessToken(token); + + // Not used in test currently + return null; +} + +export async function get_user_meta_roles(id, token) { + checkAccessToken(token); + + if (StubData.isUserAdmin(id)) { + return ["admin"]; + } else if (id) { + return ["user"]; + } else { + throw new Error(`No user id is given.`); + } +} diff --git a/src/utils/auth0_client.js b/src/utils/auth0_client.js index 10c7cd6..26aaa14 100644 --- a/src/utils/auth0_client.js +++ b/src/utils/auth0_client.js @@ -1,7 +1,5 @@ import axios from "axios"; -import dotenv from "dotenv-defaults"; - -dotenv.config(); +import "dotenv-defaults/config"; const get_token = async () => { let options = { diff --git a/src/utils/webhook_client.js b/src/utils/webhook_client.js index 6ed65c0..06f47cf 100644 --- a/src/utils/webhook_client.js +++ b/src/utils/webhook_client.js @@ -1,6 +1,5 @@ -import dotenv from "dotenv-defaults"; +import "dotenv-defaults/config"; import axios from "axios"; -dotenv.config(); const msg_tmpl = { content: "", diff --git a/yarn.lock b/yarn.lock index c41c187..c7e76c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,14 @@ # yarn lockfile v1 +"@ampproject/remapping@^2.1.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + "@babel/cli@^7.16.0": version "7.16.0" resolved "https://registry.npmjs.org/@babel/cli/-/cli-7.16.0.tgz" @@ -18,6 +26,13 @@ "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3" chokidar "^3.4.0" +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + "@babel/code-frame@^7.16.0": version "7.16.0" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz" @@ -30,6 +45,32 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz" integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q== +"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d" + integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.10.tgz#39ad504991d77f1f3da91be0b8b949a5bc466fb8" + integrity sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.10" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-module-transforms" "^7.18.9" + "@babel/helpers" "^7.18.9" + "@babel/parser" "^7.18.10" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.18.10" + "@babel/types" "^7.18.10" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" + "@babel/core@^7.16.0": version "7.16.5" resolved "https://registry.npmjs.org/@babel/core/-/core-7.16.5.tgz" @@ -60,6 +101,15 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@^7.18.10", "@babel/generator@^7.7.2": + version "7.18.12" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.12.tgz#fa58daa303757bd6f5e4bbca91b342040463d9f4" + integrity sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg== + dependencies: + "@babel/types" "^7.18.10" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" + "@babel/helper-annotate-as-pure@^7.16.0": version "7.16.0" resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz" @@ -85,6 +135,16 @@ browserslist "^4.17.5" semver "^6.3.0" +"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf" + integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg== + dependencies: + "@babel/compat-data" "^7.18.8" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.20.2" + semver "^6.3.0" + "@babel/helper-create-class-features-plugin@^7.16.5": version "7.16.5" resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.5.tgz" @@ -120,6 +180,18 @@ resolve "^1.14.2" semver "^6.1.2" +"@babel/helper-define-polyfill-provider@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.2.tgz#bd10d0aca18e8ce012755395b05a79f45eca5073" + integrity sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg== + dependencies: + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-plugin-utils" "^7.16.7" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + "@babel/helper-environment-visitor@^7.16.5": version "7.16.5" resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.5.tgz" @@ -127,6 +199,11 @@ dependencies: "@babel/types" "^7.16.0" +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + "@babel/helper-explode-assignable-expression@^7.16.0": version "7.16.0" resolved "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz" @@ -143,6 +220,14 @@ "@babel/template" "^7.16.0" "@babel/types" "^7.16.0" +"@babel/helper-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz#940e6084a55dee867d33b4e487da2676365e86b0" + integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A== + dependencies: + "@babel/template" "^7.18.6" + "@babel/types" "^7.18.9" + "@babel/helper-get-function-arity@^7.16.0": version "7.16.0" resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz" @@ -157,6 +242,13 @@ dependencies: "@babel/types" "^7.16.0" +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + "@babel/helper-member-expression-to-functions@^7.16.5": version "7.16.5" resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.5.tgz" @@ -171,6 +263,13 @@ dependencies: "@babel/types" "^7.16.0" +"@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + "@babel/helper-module-transforms@^7.16.5": version "7.16.5" resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.5.tgz" @@ -185,6 +284,20 @@ "@babel/traverse" "^7.16.5" "@babel/types" "^7.16.0" +"@babel/helper-module-transforms@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz#5a1079c005135ed627442df31a42887e80fcb712" + integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.18.6" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + "@babel/helper-optimise-call-expression@^7.16.0": version "7.16.0" resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz" @@ -197,6 +310,11 @@ resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz" integrity sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ== +"@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f" + integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w== + "@babel/helper-remap-async-to-generator@^7.16.5": version "7.16.5" resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.5.tgz" @@ -224,6 +342,13 @@ dependencies: "@babel/types" "^7.16.0" +"@babel/helper-simple-access@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea" + integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g== + dependencies: + "@babel/types" "^7.18.6" + "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": version "7.16.0" resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz" @@ -238,16 +363,38 @@ dependencies: "@babel/types" "^7.16.0" +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56" + integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw== + "@babel/helper-validator-identifier@^7.15.7": version "7.15.7" resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz" integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== +"@babel/helper-validator-identifier@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076" + integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== + "@babel/helper-validator-option@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz" integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== +"@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + "@babel/helper-wrap-function@^7.16.5": version "7.16.5" resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.5.tgz" @@ -267,6 +414,15 @@ "@babel/traverse" "^7.16.5" "@babel/types" "^7.16.0" +"@babel/helpers@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.9.tgz#4bef3b893f253a1eced04516824ede94dcfe7ff9" + integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ== + dependencies: + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + "@babel/highlight@^7.16.0": version "7.16.0" resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz" @@ -276,6 +432,15 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/node@^7.16.0": version "7.16.5" resolved "https://registry.npmjs.org/@babel/node/-/node-7.16.5.tgz" @@ -288,6 +453,11 @@ regenerator-runtime "^0.13.4" v8flags "^3.1.1" +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.18.11": + version "7.18.11" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.11.tgz#68bb07ab3d380affa9a3f96728df07969645d2d9" + integrity sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ== + "@babel/parser@^7.16.0", "@babel/parser@^7.16.5": version "7.16.6" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.16.6.tgz" @@ -444,7 +614,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.12.13": +"@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.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": version "7.12.13" resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== @@ -472,6 +649,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" +"@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.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" @@ -479,7 +663,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== @@ -493,7 +677,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.10.4": +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== @@ -528,13 +712,20 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-top-level-await@^7.14.5": +"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": version "7.14.5" resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz#1c09cd25795c7c2b8a4ba9ae49394576d4133285" + integrity sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-transform-arrow-functions@^7.16.0", "@babel/plugin-transform-arrow-functions@^7.16.5": version "7.16.5" resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.5.tgz" @@ -733,6 +924,18 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.5" +"@babel/plugin-transform-runtime@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.10.tgz#37d14d1fa810a368fd635d4d1476c0154144a96f" + integrity sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ== + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.9" + babel-plugin-polyfill-corejs2 "^0.3.2" + babel-plugin-polyfill-corejs3 "^0.5.3" + babel-plugin-polyfill-regenerator "^0.4.0" + semver "^6.3.0" + "@babel/plugin-transform-shorthand-properties@^7.16.5": version "7.16.5" resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.5.tgz" @@ -902,6 +1105,15 @@ "@babel/parser" "^7.16.0" "@babel/types" "^7.16.0" +"@babel/template@^7.18.10", "@babel/template@^7.18.6", "@babel/template@^7.3.3": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" + integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.10" + "@babel/types" "^7.18.10" + "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.5": version "7.16.5" resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.5.tgz" @@ -918,6 +1130,31 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.18.10", "@babel/traverse@^7.18.9", "@babel/traverse@^7.7.2": + version "7.18.11" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.11.tgz#3d51f2afbd83ecf9912bcbb5c4d94e3d2ddaa16f" + integrity sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.10" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.18.11" + "@babel/types" "^7.18.10" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.10.tgz#4908e81b6b339ca7c6b7a555a5fc29446f26dde6" + integrity sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ== + dependencies: + "@babel/helper-string-parser" "^7.18.10" + "@babel/helper-validator-identifier" "^7.18.6" + to-fast-properties "^2.0.0" + "@babel/types@^7.16.0", "@babel/types@^7.4.4": version "7.16.0" resolved "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz" @@ -926,6 +1163,11 @@ "@babel/helper-validator-identifier" "^7.15.7" 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== + "@eslint/eslintrc@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" @@ -955,6 +1197,255 @@ 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@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-28.1.3.tgz#2030606ec03a18c31803b8a36382762e447655df" + integrity sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + slash "^3.0.0" + +"@jest/core@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-28.1.3.tgz#0ebf2bd39840f1233cd5f2d1e6fc8b71bd5a1ac7" + integrity sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA== + dependencies: + "@jest/console" "^28.1.3" + "@jest/reporters" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^28.1.3" + jest-config "^28.1.3" + jest-haste-map "^28.1.3" + jest-message-util "^28.1.3" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-resolve-dependencies "^28.1.3" + jest-runner "^28.1.3" + jest-runtime "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + jest-watcher "^28.1.3" + micromatch "^4.0.4" + pretty-format "^28.1.3" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-28.1.3.tgz#abed43a6b040a4c24fdcb69eab1f97589b2d663e" + integrity sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA== + dependencies: + "@jest/fake-timers" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + jest-mock "^28.1.3" + +"@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/expect@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-28.1.3.tgz#9ac57e1d4491baca550f6bdbd232487177ad6a72" + integrity sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw== + dependencies: + expect "^28.1.3" + jest-snapshot "^28.1.3" + +"@jest/fake-timers@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-28.1.3.tgz#230255b3ad0a3d4978f1d06f70685baea91c640e" + integrity sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw== + dependencies: + "@jest/types" "^28.1.3" + "@sinonjs/fake-timers" "^9.1.2" + "@types/node" "*" + jest-message-util "^28.1.3" + jest-mock "^28.1.3" + jest-util "^28.1.3" + +"@jest/globals@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-28.1.3.tgz#a601d78ddc5fdef542728309894895b4a42dc333" + integrity sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/expect" "^28.1.3" + "@jest/types" "^28.1.3" + +"@jest/reporters@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-28.1.3.tgz#9adf6d265edafc5fc4a434cfb31e2df5a67a369a" + integrity sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@jridgewell/trace-mapping" "^0.3.13" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + jest-worker "^28.1.3" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + terminal-link "^2.0.0" + v8-to-istanbul "^9.0.1" + +"@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@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-28.1.2.tgz#7fe832b172b497d6663cdff6c13b0a920e139e24" + integrity sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww== + dependencies: + "@jridgewell/trace-mapping" "^0.3.13" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-28.1.3.tgz#5eae945fd9f4b8fcfce74d239e6f725b6bf076c5" + integrity sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg== + dependencies: + "@jest/console" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz#9d0c283d906ac599c74bde464bc0d7e6a82886c3" + integrity sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw== + dependencies: + "@jest/test-result" "^28.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + slash "^3.0.0" + +"@jest/transform@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-28.1.3.tgz#59d8098e50ab07950e0f2fc0fc7ec462371281b0" + integrity sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^28.1.3" + "@jridgewell/trace-mapping" "^0.3.13" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-regex-util "^28.0.2" + jest-util "^28.1.3" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.1" + +"@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" + +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + 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": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.0", "@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": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.15" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774" + integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": version "2.1.8-no-fsevents.3" resolved "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz" @@ -1088,11 +1579,30 @@ "@sendgrid/client" "^7.7.0" "@sendgrid/helpers" "^7.7.0" +"@sinclair/typebox@^0.24.1": + version "0.24.28" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.28.tgz#15aa0b416f82c268b1573ab653e4413c965fe794" + integrity sha512-dgJd3HLOkLmz4Bw50eZx/zJwtBq65nms3N9VBYu5LTjJ883oBFkTyXRlCB/ZGGwqYpJJHA5zW2Ibhl5ngITfow== + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^9.1.2": + version "9.1.2" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz#4eaab737fab77332ab132d396a3c0d364bd0ea8c" + integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== + dependencies: + "@sinonjs/commons" "^1.7.0" + "@szmarczak/http-timer@^1.1.2": version "1.1.2" resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz" @@ -1105,6 +1615,39 @@ resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== +"@types/babel__core@^7.1.14": + version "7.1.19" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" + integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@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.6": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.18.0.tgz#8134fd78cb39567465be65b9fdc16d378095f41f" + integrity sha512-v4Vwdko+pgymgS+A2UIaJru93zQd85vIGWObM5ekZNdXCKtDYqATlEYnWgfo86Q6I1Lh0oXnksDnMU1cwmlPDw== + dependencies: + "@babel/types" "^7.3.0" + "@types/body-parser@*": version "1.19.2" resolved "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz" @@ -1139,6 +1682,32 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/graceful-fs@^4.1.3": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + dependencies: + "@types/node" "*" + +"@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/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -1161,6 +1730,11 @@ resolved "https://registry.npmjs.org/@types/node/-/node-17.0.0.tgz" integrity sha512-eMhwJXc931Ihh4tkU+Y7GiLzT/y/DBNpNtr4yU9O2w3SYBsr9NaOPhQlLKRmoWtI54uNwuo0IOUFQjVOTZYRvw== +"@types/prettier@^2.1.5": + version "2.7.0" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.0.tgz#ea03e9f0376a4446f44797ca19d9c46c36e352dc" + integrity sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A== + "@types/qs@*": version "6.9.7" resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz" @@ -1179,6 +1753,11 @@ "@types/mime" "^1" "@types/node" "*" +"@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/uuid@8.3.1": version "8.3.1" resolved "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz" @@ -1197,6 +1776,18 @@ "@types/node" "*" "@types/webidl-conversions" "*" +"@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@^17.0.8": + version "17.0.11" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.11.tgz#5e10ca33e219807c0eee0f08b5efcba9b6a42c06" + integrity sha512-aB4y9UDUXTSMxmM4MH+YnuR0g5Cph3FLQBoWoMB21DSvFVAxRVEHEMx3TLh+zUZYMCQtKiqazz0Q4Rre31f/OA== + dependencies: + "@types/yargs-parser" "*" + abbrev@1: version "1.1.1" resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" @@ -1220,7 +1811,12 @@ acorn-walk@^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@^8.7.0, acorn@^8.7.1: +acorn@^8.7.0: + version "8.8.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" + integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== + +acorn@^8.7.1: version "8.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== @@ -1274,7 +1870,7 @@ ansi-colors@^4.1.1: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== -ansi-escapes@^4.3.0: +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: 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== @@ -1305,12 +1901,17 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: 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: version "6.1.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.1.0.tgz#87313c102b8118abd57371afab34618bf7350ed3" integrity sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ== -anymatch@~3.1.2: +anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz" integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== @@ -1356,6 +1957,11 @@ array.prototype.flat@^1.2.5: es-abstract "^1.19.2" es-shim-unscopables "^1.0.0" +asap@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== + ast-types@^0.13.2: version "0.13.4" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" @@ -1415,6 +2021,19 @@ axios@^0.27.2: follow-redirects "^1.14.9" form-data "^4.0.0" +babel-jest@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.3.tgz#c1187258197c099072156a0a121c11ee1e3917d5" + integrity sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q== + dependencies: + "@jest/transform" "^28.1.3" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^28.1.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + babel-plugin-dynamic-import-node@^2.3.3: version "2.3.3" resolved "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz" @@ -1422,6 +2041,38 @@ babel-plugin-dynamic-import-node@^2.3.3: dependencies: object.assign "^4.1.0" +babel-plugin-istanbul@^6.1.1: + 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@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz#1952c4d0ea50f2d6d794353762278d1d8cca3fbe" + integrity sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-module-resolver@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz#22a4f32f7441727ec1fbf4967b863e1e3e9f33e2" + integrity sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA== + dependencies: + find-babel-config "^1.2.0" + glob "^7.1.6" + pkg-up "^3.1.0" + reselect "^4.0.0" + resolve "^1.13.1" + babel-plugin-polyfill-corejs2@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.0.tgz" @@ -1431,6 +2082,15 @@ babel-plugin-polyfill-corejs2@^0.3.0: "@babel/helper-define-polyfill-provider" "^0.3.0" semver "^6.1.1" +babel-plugin-polyfill-corejs2@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.2.tgz#e4c31d4c89b56f3cf85b92558954c66b54bd972d" + integrity sha512-LPnodUl3lS0/4wN3Rb+m+UK8s7lj2jcLRrjho4gLw+OJs+I4bvGXshINesY5xx/apM+biTnQ9reDI8yj+0M5+Q== + dependencies: + "@babel/compat-data" "^7.17.7" + "@babel/helper-define-polyfill-provider" "^0.3.2" + semver "^6.1.1" + babel-plugin-polyfill-corejs3@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.4.0.tgz" @@ -1439,6 +2099,14 @@ babel-plugin-polyfill-corejs3@^0.4.0: "@babel/helper-define-polyfill-provider" "^0.3.0" core-js-compat "^3.18.0" +babel-plugin-polyfill-corejs3@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz#d7e09c9a899079d71a8b670c6181af56ec19c5c7" + integrity sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.2" + core-js-compat "^3.21.0" + babel-plugin-polyfill-regenerator@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.0.tgz" @@ -1446,6 +2114,39 @@ babel-plugin-polyfill-regenerator@^0.3.0: dependencies: "@babel/helper-define-polyfill-provider" "^0.3.0" +babel-plugin-polyfill-regenerator@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.0.tgz#8f51809b6d5883e07e71548d75966ff7635527fe" + integrity sha512-RW1cnryiADFeHmfLS+WW/G431p1PsW5qdRdz0SDRi7TKcUgc7Oh/uXkT7MZ/+tGsT1BkczEAmD5XjUyJ5SWDTw== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.2" + +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@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz#5dfc20b99abed5db994406c2b9ab94c73aaa419d" + integrity sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A== + dependencies: + babel-plugin-jest-hoist "^28.1.3" + babel-preset-current-node-syntax "^1.0.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" @@ -1543,6 +2244,23 @@ browserslist@^4.17.5, browserslist@^4.19.1: node-releases "^2.0.1" picocolors "^1.0.0" +browserslist@^4.20.2, browserslist@^4.21.3: + version "4.21.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a" + integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ== + dependencies: + caniuse-lite "^1.0.30001370" + electron-to-chromium "^1.4.202" + node-releases "^2.0.6" + update-browserslist-db "^1.0.5" + +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" + bson@^4.2.2, bson@^4.6.0: version "4.6.0" resolved "https://registry.npmjs.org/bson/-/bson-4.6.0.tgz" @@ -1616,6 +2334,11 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +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.2.0: version "6.2.1" resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.2.1.tgz" @@ -1626,6 +2349,11 @@ caniuse-lite@^1.0.30001286: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001366.tgz" integrity sha512-yy7XLWCubDobokgzudpkKux8e0UOOnLHE6mlNJBzT3lZJz6s5atSEzjoL+fsCPkI0G8MP5uVdDx1ur/fXEWkZA== +caniuse-lite@^1.0.30001370: + version "1.0.30001375" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001375.tgz#8e73bc3d1a4c800beb39f3163bf0190d7e5d7672" + integrity sha512-kWIMkNzLYxSvnjy0hL8w1NOaWNr2rn39RTAVyIwcw8juu60bZDWiF1/loOYANzjtJmy6qPgNmn38ro5Pygagdw== + chalk@3.0.0, chalk@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" @@ -1651,6 +2379,11 @@ chalk@^4.0.0, chalk@^4.1.0: 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== + charm@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/charm/-/charm-0.1.2.tgz#06c21eed1a1b06aeb67553cdc53e23274bac2296" @@ -1691,6 +2424,16 @@ ci-info@^2.0.0: resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +ci-info@^3.2.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.2.tgz#6d2967ffa407466481c6c90b6e16b3098f080128" + integrity sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg== + +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -1731,6 +2474,15 @@ cli-truncate@^3.1.0: slice-ansi "^5.0.0" string-width "^5.0.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" + clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz" @@ -1747,6 +2499,16 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" +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.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" @@ -1803,6 +2565,11 @@ commondir@^1.0.1: resolved "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= +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.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" @@ -1840,7 +2607,7 @@ continuation-local-storage@^3.2.1: async-listener "^0.6.0" emitter-listener "^1.1.1" -convert-source-map@^1.1.0, convert-source-map@^1.7.0: +convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.8.0" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz" integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== @@ -1857,6 +2624,11 @@ cookie@0.4.0: resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== +cookiejar@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.3.tgz#fc7a6216e408e74414b90230050842dacda75acc" + integrity sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ== + core-js-compat@^3.18.0, core-js-compat@^3.19.1: version "3.20.0" resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.20.0.tgz" @@ -1865,6 +2637,14 @@ core-js-compat@^3.18.0, core-js-compat@^3.19.1: browserslist "^4.19.1" semver "7.0.0" +core-js-compat@^3.21.0: + version "3.24.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.24.1.tgz#d1af84a17e18dfdd401ee39da9996f9a7ba887de" + integrity sha512-XhdNAGeRnTpp8xbD+sR/HFDK9CbeeeqXT6TuofXh3urqEevzkWmLRgrVoykodsw8okqo2pu1BOmuCKrHx63zdw== + dependencies: + browserslist "^4.21.3" + semver "7.0.0" + core-js@^3.19.0: version "3.20.0" resolved "https://registry.npmjs.org/core-js/-/core-js-3.20.0.tgz" @@ -1945,6 +2725,11 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== + deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" @@ -2015,6 +2800,24 @@ destroy@~1.0.4: resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +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== + +dezalgo@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + integrity sha512-K7i4zNfT2kgQz3GylDw40ot9GAE47sFZ9EXHFSPP6zONLgH6kWXE0KWJchkbQJLBkRazq4APwZ4OwiFFlT95OQ== + dependencies: + asap "^2.0.0" + wrappy "1" + +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== + doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -2075,6 +2878,11 @@ electron-to-chromium@^1.4.17: resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.20.tgz" integrity sha512-N7ZVNrdzX8NE90OXEFBMsBf3fp8P/vVDUER3WCUZjzC7OkNTXHVoF6W9qVhq8+dA8tGnbDajzUpj2ISNVVyj+Q== +electron-to-chromium@^1.4.202: + version "1.4.218" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.218.tgz#d6b817b5454499a92c85888b42dc2ad075e4493a" + integrity sha512-INDylKH//YIf2w67D+IjkfVnGVrZ/D94DAU/FPPm6T4jEPbEDQvo9r2wTj0ncFdtJH8+V8BggZTaN8Rzk5wkgw== + emitter-listener@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8" @@ -2082,6 +2890,11 @@ emitter-listener@^1.1.1: dependencies: shimmer "^1.2.0" +emittery@^0.10.2: + version "0.10.2" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933" + integrity sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" @@ -2111,6 +2924,13 @@ enquirer@2.3.6: dependencies: ansi-colors "^4.1.1" +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" + es-abstract@^1.19.0, es-abstract@^1.19.2, es-abstract@^1.19.5: version "1.20.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814" @@ -2202,6 +3022,11 @@ escape-string-regexp@^1.0.5: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +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" @@ -2430,15 +3255,30 @@ eventemitter2@5.0.1, eventemitter2@~5.0.1: integrity sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg== eventemitter2@^6.3.1: - version "6.4.6" - resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.6.tgz#92d56569cc147a4d9b9da9e942e89b20ce236b0a" - integrity sha512-OHqo4wbHX5VbvlbB6o6eDwhYmiTjrpWACjF8Pmof/GTD6rdBNdZFNck3xlhqOiQFGCOoq3uzHvA0cQpFHIGVAQ== + version "6.4.7" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.7.tgz#a7f6c4d7abf28a14c1ef3442f21cb306a054271d" + integrity sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg== eventemitter2@~0.4.14: version "0.4.14" resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab" integrity sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ== +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" + execa@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/execa/-/execa-6.1.0.tgz#cea16dee211ff011246556388effa0818394fb20" @@ -2454,6 +3294,22 @@ execa@^6.1.0: signal-exit "^3.0.7" strip-final-newline "^3.0.0" +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== + +expect@^28.1.3: + 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" + express-jwt@^6.1.0: version "6.1.2" resolved "https://registry.npmjs.org/express-jwt/-/express-jwt-6.1.2.tgz" @@ -2537,6 +3393,18 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +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== + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + fclone@1.0.11, fclone@~1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/fclone/-/fclone-1.0.11.tgz#10e85da38bfea7fc599341c296ee1d77266ee640" @@ -2574,6 +3442,14 @@ finalhandler@~1.1.2: statuses "~1.5.0" unpipe "~1.0.0" +find-babel-config@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-1.2.0.tgz#a9b7b317eb5b9860cda9d54740a8c8337a2283a2" + integrity sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA== + dependencies: + json5 "^0.5.1" + path-exists "^3.0.0" + find-cache-dir@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz" @@ -2597,6 +3473,14 @@ find-up@^3.0.0: 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" + flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -2624,6 +3508,16 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +formidable@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.0.1.tgz#4310bc7965d185536f9565184dee74fbb75557ff" + integrity sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ== + dependencies: + dezalgo "1.0.3" + hexoid "1.0.0" + once "1.4.0" + qs "6.9.3" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" @@ -2653,7 +3547,7 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@~2.3.2: +fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -2696,6 +3590,11 @@ gensync@^1.0.0-beta.2: resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== +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, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz" @@ -2705,6 +3604,11 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.1" +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-stream@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz" @@ -2719,7 +3623,7 @@ get-stream@^5.1.0: dependencies: pump "^3.0.0" -get-stream@^6.0.1: +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== @@ -2780,7 +3684,7 @@ glob@^7.0.0: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.5, glob@^7.1.3: +glob@^7.0.5, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -2833,7 +3737,7 @@ graceful-fs@^4.1.2: resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== -graceful-fs@^4.1.6, graceful-fs@^4.2.0: +graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== @@ -2894,6 +3798,11 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +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== + homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz" @@ -2901,6 +3810,11 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" +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-cache-semantics@^4.0.0: version "4.1.0" resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz" @@ -2967,6 +3881,11 @@ https-proxy-agent@5, https-proxy-agent@^5.0.0: agent-base "6" debug "4" +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@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-3.0.1.tgz#c740920859dafa50e5a3222da9d3bf4bb0e5eef5" @@ -3012,6 +3931,14 @@ import-lazy@^2.1.0: resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz" integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= +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" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" @@ -3030,7 +3957,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@~2.0.1: +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.1: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -3064,11 +3991,21 @@ ip@^1.1.5: resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.8.tgz#ae05948f6b075435ed3307acce04629da8cdbf48" integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg== +ip@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" + integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +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-bigint@^1.0.1: version "1.0.4" resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" @@ -3139,6 +4076,11 @@ is-fullwidth-code-point@^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-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.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" @@ -3213,6 +4155,11 @@ is-shared-array-buffer@^1.0.2: dependencies: call-bind "^1.0.2" +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" @@ -3264,6 +4211,406 @@ isobject@^3.0.1: resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +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@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz#31d18bdd127f825dd02ea7bfdfd906f8ab840e9f" + integrity sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A== + 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.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.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.1.3: + version "3.1.5" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" + integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-28.1.3.tgz#d9aeee6792be3686c47cb988a8eaf82ff4238831" + integrity sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA== + dependencies: + execa "^5.0.0" + p-limit "^3.1.0" + +jest-circus@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-28.1.3.tgz#d14bd11cf8ee1a03d69902dc47b6bd4634ee00e4" + integrity sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/expect" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + is-generator-fn "^2.0.0" + jest-each "^28.1.3" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-runtime "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + p-limit "^3.1.0" + pretty-format "^28.1.3" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.3.tgz#558b33c577d06de55087b8448d373b9f654e46b2" + integrity sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ== + dependencies: + "@jest/core" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + prompts "^2.0.1" + yargs "^17.3.1" + +jest-config@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-28.1.3.tgz#e315e1f73df3cac31447eed8b8740a477392ec60" + integrity sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^28.1.3" + "@jest/types" "^28.1.3" + babel-jest "^28.1.3" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^28.1.3" + jest-environment-node "^28.1.3" + jest-get-type "^28.0.2" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-runner "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^28.1.3" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +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@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-28.1.1.tgz#6f515c3bf841516d82ecd57a62eed9204c2f42a8" + integrity sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA== + dependencies: + detect-newline "^3.0.0" + +jest-each@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-28.1.3.tgz#bdd1516edbe2b1f3569cfdad9acd543040028f81" + integrity sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g== + dependencies: + "@jest/types" "^28.1.3" + chalk "^4.0.0" + jest-get-type "^28.0.2" + jest-util "^28.1.3" + pretty-format "^28.1.3" + +jest-environment-node@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-28.1.3.tgz#7e74fe40eb645b9d56c0c4b70ca4357faa349be5" + integrity sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/fake-timers" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + jest-mock "^28.1.3" + jest-util "^28.1.3" + +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@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-28.1.3.tgz#abd5451129a38d9841049644f34b034308944e2b" + integrity sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA== + dependencies: + "@jest/types" "^28.1.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^28.0.2" + jest-util "^28.1.3" + jest-worker "^28.1.3" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz#a6685d9b074be99e3adee816ce84fd30795e654d" + integrity sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA== + dependencies: + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + +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@^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@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-28.1.3.tgz#d4e9b1fc838bea595c77ab73672ebf513ab249da" + integrity sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + +jest-regex-util@^28.0.2: + version "28.0.2" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-28.0.2.tgz#afdc377a3b25fb6e80825adcf76c854e5bf47ead" + integrity sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw== + +jest-resolve-dependencies@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz#8c65d7583460df7275c6ea2791901fa975c1fe66" + integrity sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA== + dependencies: + jest-regex-util "^28.0.2" + jest-snapshot "^28.1.3" + +jest-resolve@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-28.1.3.tgz#cfb36100341ddbb061ec781426b3c31eb51aa0a8" + integrity sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-pnp-resolver "^1.2.2" + jest-util "^28.1.3" + jest-validate "^28.1.3" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-runner@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-28.1.3.tgz#5eee25febd730b4713a2cdfd76bdd5557840f9a1" + integrity sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA== + dependencies: + "@jest/console" "^28.1.3" + "@jest/environment" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.10.2" + graceful-fs "^4.2.9" + jest-docblock "^28.1.1" + jest-environment-node "^28.1.3" + jest-haste-map "^28.1.3" + jest-leak-detector "^28.1.3" + jest-message-util "^28.1.3" + jest-resolve "^28.1.3" + jest-runtime "^28.1.3" + jest-util "^28.1.3" + jest-watcher "^28.1.3" + jest-worker "^28.1.3" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-28.1.3.tgz#a57643458235aa53e8ec7821949e728960d0605f" + integrity sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/fake-timers" "^28.1.3" + "@jest/globals" "^28.1.3" + "@jest/source-map" "^28.1.2" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-message-util "^28.1.3" + jest-mock "^28.1.3" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-28.1.3.tgz#17467b3ab8ddb81e2f605db05583d69388fc0668" + integrity sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/babel__traverse" "^7.0.6" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^28.1.3" + graceful-fs "^4.2.9" + jest-diff "^28.1.3" + jest-get-type "^28.0.2" + jest-haste-map "^28.1.3" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + natural-compare "^1.4.0" + pretty-format "^28.1.3" + semver "^7.3.5" + +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@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-28.1.3.tgz#e322267fd5e7c64cea4629612c357bbda96229df" + integrity sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA== + dependencies: + "@jest/types" "^28.1.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^28.0.2" + leven "^3.1.0" + pretty-format "^28.1.3" + +jest-watcher@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-28.1.3.tgz#c6023a59ba2255e3b4c57179fc94164b3e73abd4" + integrity sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g== + dependencies: + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.10.2" + jest-util "^28.1.3" + string-length "^4.0.1" + +jest-worker@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-28.1.3.tgz#7e3c4ce3fa23d1bb6accb169e7f396f98ed4bb98" + integrity sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest/-/jest-28.1.3.tgz#e9c6a7eecdebe3548ca2b18894a50f45b36dfc6b" + integrity sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA== + dependencies: + "@jest/core" "^28.1.3" + "@jest/types" "^28.1.3" + import-local "^3.0.2" + jest-cli "^28.1.3" + jose@^2.0.5: version "2.0.5" resolved "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz" @@ -3291,6 +4638,14 @@ js-tokens@^4.0.0: resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +js-yaml@^3.13.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" @@ -3313,6 +4668,11 @@ json-buffer@3.0.0: resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz" integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= +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" @@ -3328,6 +4688,11 @@ json-stringify-safe@^5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== +json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + integrity sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw== + json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -3342,6 +4707,11 @@ json5@^2.1.2: dependencies: minimist "^1.2.5" +json5@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -3411,6 +4781,11 @@ kind-of@^6.0.2: resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" 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== + latest-version@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz" @@ -3423,6 +4798,11 @@ lazy@~1.0.11: resolved "https://registry.yarnpkg.com/lazy/-/lazy-1.0.11.tgz#daa068206282542c088288e975c297c1ae77b690" integrity sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA== +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" @@ -3449,6 +4829,11 @@ limiter@^1.1.5: resolved "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz" integrity sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA== +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.0.3: version "13.0.3" resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.0.3.tgz#d7cdf03a3830b327a2b63c6aec953d71d9dc48c6" @@ -3498,6 +4883,13 @@ locate-path@^3.0.0: 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" + lodash.clonedeep@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz" @@ -3623,6 +5015,13 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" +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" + media-typer@0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" @@ -3643,12 +5042,12 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -methods@~1.1.2: +methods@^1.1.2, methods@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micromatch@^4.0.5: +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== @@ -3685,6 +5084,11 @@ mime@1.6.0: resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" 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" @@ -3834,11 +5238,21 @@ node-environment-flags@^1.0.5: object.getownpropertydescriptors "^2.0.3" semver "^5.7.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-releases@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz" integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== +node-releases@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" + integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== + nodemon@^2.0.15: version "2.0.15" resolved "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz" @@ -3872,6 +5286,13 @@ normalize-url@^4.1.0: resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz" integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== +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" @@ -3942,14 +5363,14 @@ on-finished@~2.3.0: dependencies: ee-first "1.1.1" -once@^1.3.0, once@^1.3.1, once@^1.4.0: +once@1.4.0, once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" -onetime@^5.1.0: +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== @@ -3999,13 +5420,20 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0: +p-limit@^2.0.0, p-limit@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== dependencies: p-try "^2.0.0" +p-limit@^3.1.0: + 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-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -4020,6 +5448,13 @@ p-locate@^3.0.0: 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-map@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" @@ -4083,6 +5518,16 @@ parent-module@^1.0.0: dependencies: callsites "^3.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" + parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz" @@ -4098,12 +5543,17 @@ path-exists@^3.0.0: resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= +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-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-key@^3.1.0: +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== @@ -4133,7 +5583,7 @@ picomatch@^2.0.4, picomatch@^2.2.1: resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== -picomatch@^2.3.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== @@ -4167,6 +5617,11 @@ pirates@^4.0.0: resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz" integrity sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw== +pirates@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" + integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz" @@ -4174,6 +5629,20 @@ pkg-dir@^3.0.0: dependencies: find-up "^3.0.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" + +pkg-up@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + pm2-axon-rpc@~0.7.0, pm2-axon-rpc@~0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/pm2-axon-rpc/-/pm2-axon-rpc-0.7.1.tgz#2daec5383a63135b3f18babb70266dacdcbc429a" @@ -4281,6 +5750,16 @@ prettier@^2.7.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== +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" + prisma@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/prisma/-/prisma-4.0.0.tgz" @@ -4295,6 +5774,14 @@ promptly@^2: dependencies: read "^1.0.4" +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" + proxy-addr@~2.0.5: version "2.0.7" resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" @@ -4357,11 +5844,23 @@ qs@6.7.0: resolved "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== +qs@6.9.3: + version "6.9.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.3.tgz#bfadcd296c2d549f1dffa560619132c977f5008e" + integrity sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw== + qs@6.9.6: version "6.9.6" resolved "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz" integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ== +qs@^6.10.3: + 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" + range-parser@~1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" @@ -4407,6 +5906,11 @@ rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" +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@^1.0.4: version "1.0.7" resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" @@ -4424,6 +5928,15 @@ readable-stream@1.1.x: isarray "0.0.1" string_decoder "~0.10.x" +readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" @@ -4512,21 +6025,48 @@ regjsparser@^0.7.0: dependencies: jsesc "~0.5.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-in-the-middle@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/require-in-the-middle/-/require-in-the-middle-5.1.0.tgz#b768f800377b47526d026bbf5a7f727f16eb412f" - integrity sha512-M2rLKVupQfJ5lf9OvqFGIT+9iVLnTmjgbOmpil12hiSQNn5zJTKGPoIisETNjfK+09vP3rpm1zJajmErpr2sEQ== + version "5.2.0" + resolved "https://registry.yarnpkg.com/require-in-the-middle/-/require-in-the-middle-5.2.0.tgz#4b71e3cc7f59977100af9beb76bf2d056a5a6de2" + integrity sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg== dependencies: debug "^4.1.1" module-details-from-path "^1.0.3" - resolve "^1.12.0" + resolve "^1.22.1" + +reselect@^4.0.0: + version "4.1.6" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.6.tgz#19ca2d3d0b35373a74dc1c98692cdaffb6602656" + integrity sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ== + +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@^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@^1.10.1, resolve@^1.12.0, resolve@^1.20.0, resolve@^1.22.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.exports@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" + integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== + +resolve@^1.10.1, resolve@^1.13.1, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.22.1: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -4563,7 +6103,7 @@ rfdc@^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== @@ -4587,7 +6127,7 @@ safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@~5.1.1: resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.2.1: +safe-buffer@^5.2.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== @@ -4631,7 +6171,7 @@ semver@^5.3.0, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^7.0.0, semver@^7.2, semver@^7.3.7: +semver@^7.0.0, semver@^7.2, semver@^7.3.5, semver@^7.3.7: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== @@ -4737,11 +6277,21 @@ signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +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@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz" integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== +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@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" @@ -4788,13 +6338,21 @@ socks-proxy-agent@5, socks-proxy-agent@^5.0.0: socks "^2.3.3" socks@^2.3.3: - version "2.6.2" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.2.tgz#ec042d7960073d40d94268ff3bb727dc685f111a" - integrity sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA== + version "2.7.0" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.0.tgz#f9225acdb841e874dca25f870e9130990f3913d0" + integrity sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA== dependencies: - ip "^1.1.5" + ip "^2.0.0" smart-buffer "^4.2.0" +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-support@0.5.19: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" @@ -4816,7 +6374,7 @@ source-map@^0.5.0: resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -source-map@^0.6.0, source-map@~0.6.1: +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -4838,6 +6396,13 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== +stack-utils@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + dependencies: + escape-string-regexp "^2.0.0" + statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" @@ -4853,7 +6418,15 @@ string-argv@^0.3.1: resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== -string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2: +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.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -4905,6 +6478,13 @@ string.prototype.trimstart@^1.0.5: define-properties "^1.1.4" es-abstract "^1.19.5" +string_decoder@^1.1.1: + 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" @@ -4929,6 +6509,16 @@ strip-bom@^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-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" @@ -4944,6 +6534,31 @@ strip-json-comments@~2.0.1: resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +superagent@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-8.0.0.tgz#2ea4587df4b81ef023ec01ebc6e1bcb9e2344cb6" + integrity sha512-iudipXEel+SzlP9y29UBWGDjB+Zzag+eeA1iLosaR2YHBRr1Q1kC29iBrF2zIVD9fqVbpZnXkN/VJmwFMVyNWg== + 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" + +supertest@^6.2.4: + version "6.2.4" + resolved "https://registry.yarnpkg.com/supertest/-/supertest-6.2.4.tgz#3dcebe42f7fd6f28dd7ac74c6cba881f7101b2f0" + integrity sha512-M8xVnCNv+q2T2WXVzxDECvL2695Uv2uUj2O0utxsld/HRyJvOU8W9f1gvsYxSNU4wmIe0/L/ItnpU4iKq0emDA== + dependencies: + methods "^1.1.2" + superagent "^8.0.0" + supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" @@ -4951,22 +6566,54 @@ supports-color@^5.3.0, supports-color@^5.5.0: dependencies: has-flag "^3.0.0" -supports-color@^7.1.0: +supports-color@^7.0.0, supports-color@^7.1.0: version "7.2.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + 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== systeminformation@^5.7: - version "5.12.1" - resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.12.1.tgz#8e512e4f9f21caaaa5f802fcb6a337cb4dc8b2f5" - integrity sha512-qAV0xSeSJlg0ZHmQ1T2rLrL54SATalBx6v4T8Sd5s17pEm6saX3LKzlPhfPx+EfT91y9yhRYnKhnMoLTFkxbqw== + version "5.12.6" + resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.12.6.tgz#b75d7aaf9f5da32439fc633d2be9eb741691d200" + integrity sha512-FkCvT5BOuH1OE3+8lFM25oXIYJ0CM8kq4Wgvz2jyBTrsOIgha/6gdJXgbF4rv+g0j/5wJqQLDKan7kc/p7uIvw== + +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-table@^0.2.0: version "0.2.0" @@ -4978,6 +6625,11 @@ through@^2.3.8: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +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.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" @@ -5065,6 +6717,11 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +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.20.2: version "0.20.2" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" @@ -5155,6 +6812,14 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= +update-browserslist-db@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38" + integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + update-notifier@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz" @@ -5189,6 +6854,11 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" +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.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" @@ -5217,6 +6887,15 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +v8-to-istanbul@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4" + integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + v8flags@^3.1.1: version "3.2.0" resolved "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz" @@ -5240,13 +6919,20 @@ vizion@~2.2.1: js-git "^0.7.8" vm2@^3.9.8: - version "3.9.10" - resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.10.tgz#c66543096b5c44c8861a6465805c23c7cc996a44" - integrity sha512-AuECTSvwu2OHLAZYhG716YzwodKCIJxB6u1zG7PgSQwIgAlEaoXH52bxdcvT8GkGjnYK7r7yWDW0m0sOsPuBjQ== + version "3.9.11" + resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.11.tgz#a880f510a606481719ec3f9803b940c5805a06fe" + integrity sha512-PFG8iJRSjvvBdisowQ7iVF580DXb1uCIiGaXgm7tynMR1uTBlv7UJlB1zdv5KJ+Tmq1f0Upnj3fayoEOPpCBKg== dependencies: acorn "^8.7.0" acorn-walk "^8.2.0" +walker@^1.0.8: + 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" + webidl-conversions@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz" @@ -5323,10 +7009,18 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" +write-file-atomic@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.1.tgz#9faa33a964c1c85ff6f849b80b42a88c2c537c8f" + integrity sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + ws@^7.0.0: - version "7.5.8" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.8.tgz#ac2729881ab9e7cbaf8787fe3469a48c5c7f636a" - integrity sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw== + version "7.5.9" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== ws@~7.4.0: version "7.4.6" @@ -5343,6 +7037,11 @@ xregexp@2.0.0: resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" integrity sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA== +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== + yallist@^2.0.0: version "2.1.2" resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz" @@ -5371,7 +7070,30 @@ yamljs@0.3.0: argparse "^1.0.7" glob "^7.0.5" +yargs-parser@^21.0.0: + 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@^17.3.1: + version "17.5.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" + integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== + dependencies: + cliui "^7.0.2" + 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.0.0" + yarn@^1.22.17: version "1.22.17" resolved "https://registry.npmjs.org/yarn/-/yarn-1.22.17.tgz" integrity sha512-H0p241BXaH0UN9IeH//RT82tl5PfNraVpSpEoW+ET7lmopNC61eZ+A+IDvU8FM6Go5vx162SncDL8J1ZjRBriQ== + +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==